diff --git a/contracts/mutants/AggregatorProxy/1/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..5899fbb57cc --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/CCD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/CCD/AggregatorProxy.sol new file mode 100644 index 00000000000..71c3d80fc56 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/CCD/AggregatorProxy.sol @@ -0,0 +1,420 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/CSC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/CSC/AggregatorProxy.sol new file mode 100644 index 00000000000..9c36441e3c8 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/CSC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (true) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/DLR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/DLR/AggregatorProxy.sol new file mode 100644 index 00000000000..7c14584ffab --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/DLR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase storage phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/DOD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/DOD/AggregatorProxy.sol new file mode 100644 index 00000000000..1f58dd1c92e --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/DOD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/ECS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/ECS/AggregatorProxy.sol new file mode 100644 index 00000000000..7ef9205c32d --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/ECS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint8(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/EHC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/EHC/AggregatorProxy.sol new file mode 100644 index 00000000000..038070990a8 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/EHC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + /* require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); */ + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..6636046bb22 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..472f500e44e --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/MOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/MOR/AggregatorProxy.sol new file mode 100644 index 00000000000..eba7bc8deaa --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/MOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..0033bb9fa49 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/ORFD/AggregatorProxy.sol @@ -0,0 +1,414 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..62ab0124557 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/RVS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/RVS/AggregatorProxy.sol new file mode 100644 index 00000000000..60f250d9bc1 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/RVS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (aggregatorRoundId, phaseId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/SCEC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/SCEC/AggregatorProxy.sol new file mode 100644 index 00000000000..60f250d9bc1 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/SCEC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (aggregatorRoundId, phaseId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/1/VVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/1/VVR/AggregatorProxy.sol new file mode 100644 index 00000000000..df77983d412 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/1/VVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase public currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/10/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/10/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..c1a2d99b29b --- /dev/null +++ b/contracts/mutants/AggregatorProxy/10/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator <= address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id - 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) >> PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/10/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/10/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..9d2f7079ddb --- /dev/null +++ b/contracts/mutants/AggregatorProxy/10/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 1; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 1; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/10/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/10/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..e7c7e780cb1 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/10/ORFD/AggregatorProxy.sol @@ -0,0 +1,306 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/10/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/10/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..5566c0f9181 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/10/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getAnswer(aggregatorRoundId); */ + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getTimestamp(aggregatorRoundId); */ + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + /* return addPhase(phase.id, uint64(phase.aggregator.latestRound())); */ + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + /* return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); */ + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..aea8eafdf35 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/CSC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/CSC/AggregatorProxy.sol new file mode 100644 index 00000000000..3388b99e1bb --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/CSC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (true) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (true) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/DLR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/DLR/AggregatorProxy.sol new file mode 100644 index 00000000000..4a75d05ffd4 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/DLR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase storage phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase storage current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/ECS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/ECS/AggregatorProxy.sol new file mode 100644 index 00000000000..b11ac89e6d5 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/ECS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint8(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint8((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/EHC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/EHC/AggregatorProxy.sol new file mode 100644 index 00000000000..9d2d2b42c25 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/EHC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + /* require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); */ + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + /* require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); */ + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..98157532a57 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..8b1d824bbc0 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/MOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/MOR/AggregatorProxy.sol new file mode 100644 index 00000000000..7f86e6db9cb --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/MOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..c6b01417933 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/ORFD/AggregatorProxy.sol @@ -0,0 +1,406 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..38537b828f5 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/RVS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/RVS/AggregatorProxy.sol new file mode 100644 index 00000000000..308c71a09a3 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/RVS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (aggregatorRoundId, phaseId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + updatedAt, uint64(roundId)), + addPhase(phaseId, + answer, + startedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/SCEC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/SCEC/AggregatorProxy.sol new file mode 100644 index 00000000000..308c71a09a3 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/SCEC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (aggregatorRoundId, phaseId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + updatedAt, uint64(roundId)), + addPhase(phaseId, + answer, + startedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/2/VVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/2/VVR/AggregatorProxy.sol new file mode 100644 index 00000000000..cad04cf71d3 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/2/VVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase public currentPhase; + AggregatorV2V3Interface internal proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..72ff80e44cf --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/CSC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/CSC/AggregatorProxy.sol new file mode 100644 index 00000000000..7d97f677a02 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/CSC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (true) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (true) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (true) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/DLR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/DLR/AggregatorProxy.sol new file mode 100644 index 00000000000..56d831c9ce4 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/DLR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase storage phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase storage current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string storage) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/ECS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/ECS/AggregatorProxy.sol new file mode 100644 index 00000000000..768d9531e75 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/ECS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint8(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint8((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint8(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..2b20debda45 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..0e78d842bd9 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/MOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/MOR/AggregatorProxy.sol new file mode 100644 index 00000000000..abafb3f49a6 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/MOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external Owned() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..b999d91e2d1 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/ORFD/AggregatorProxy.sol @@ -0,0 +1,392 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..09037eb66a5 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/3/VVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/3/VVR/AggregatorProxy.sol new file mode 100644 index 00000000000..300ad434c82 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/3/VVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase public currentPhase; + AggregatorV2V3Interface internal proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 public constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..549b881f303 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/CSC/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/CSC/AggregatorProxy.sol new file mode 100644 index 00000000000..17e6d987c34 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/CSC/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (true) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (true) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (true) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (true) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/ECS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/ECS/AggregatorProxy.sol new file mode 100644 index 00000000000..23e547c8234 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/ECS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint8(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint8((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint8(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint8(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..2785a19e1d9 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) public onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..a19172eaf5f --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/MOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/MOR/AggregatorProxy.sol new file mode 100644 index 00000000000..ee73470cfa0 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/MOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + Owned() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external Owned() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external Owned() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..6cd98df270c --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/ORFD/AggregatorProxy.sol @@ -0,0 +1,378 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..348138ed636 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/4/VVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/4/VVR/AggregatorProxy.sol new file mode 100644 index 00000000000..f8470106645 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/4/VVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase public currentPhase; + AggregatorV2V3Interface internal proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 public constant PHASE_OFFSET = 64; + uint256 public constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..3e47f7173a2 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/ECS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/ECS/AggregatorProxy.sol new file mode 100644 index 00000000000..9357c4f8e96 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/ECS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint8(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint8((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint8(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint8(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint8(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..552a5cc17e8 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) public onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) public onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..01f8ac76440 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..a33b8a3e5ea --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/ORFD/AggregatorProxy.sol @@ -0,0 +1,369 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..1888ec4a74c --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getAnswer(aggregatorRoundId); */ + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/5/VVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/5/VVR/AggregatorProxy.sol new file mode 100644 index 00000000000..9c4cd99bd4b --- /dev/null +++ b/contracts/mutants/AggregatorProxy/5/VVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase public currentPhase; + AggregatorV2V3Interface internal proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 public constant PHASE_OFFSET = 64; + uint256 public constant PHASE_SIZE = 16; + uint256 public constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/6/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/6/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..c67dfb5f8c1 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/6/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/6/ECS/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/6/ECS/AggregatorProxy.sol new file mode 100644 index 00000000000..ab35374622f --- /dev/null +++ b/contracts/mutants/AggregatorProxy/6/ECS/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint8(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint8((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint8(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint8(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint8(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint8(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/6/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/6/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..86e9ff8d531 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/6/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) public onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) public onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) public { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/6/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/6/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..685d86066a1 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/6/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/6/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/6/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..15af47b5a7d --- /dev/null +++ b/contracts/mutants/AggregatorProxy/6/ORFD/AggregatorProxy.sol @@ -0,0 +1,344 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/6/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/6/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..201bc4875d9 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/6/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getAnswer(aggregatorRoundId); */ + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/7/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/7/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..526e6e4f783 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/7/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/7/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/7/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..12c0e4bbe73 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/7/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) public onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) public onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) public { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + public + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/7/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/7/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..738a6b56468 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/7/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 1; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/7/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/7/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..f9096058a7d --- /dev/null +++ b/contracts/mutants/AggregatorProxy/7/ORFD/AggregatorProxy.sol @@ -0,0 +1,312 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/7/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/7/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..3c12054cea5 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/7/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getAnswer(aggregatorRoundId); */ + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/8/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/8/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..c8d65391ef5 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/8/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator <= address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/8/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/8/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..2455bcd244f --- /dev/null +++ b/contracts/mutants/AggregatorProxy/8/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) public onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) public onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) public { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + public + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) public view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/8/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/8/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..ab70017b625 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/8/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 1; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/8/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/8/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..98edb438717 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/8/ORFD/AggregatorProxy.sol @@ -0,0 +1,310 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/8/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/8/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..edaa3857dba --- /dev/null +++ b/contracts/mutants/AggregatorProxy/8/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getAnswer(aggregatorRoundId); */ + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getTimestamp(aggregatorRoundId); */ + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/9/BOR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/9/BOR/AggregatorProxy.sol new file mode 100644 index 00000000000..4b00fa33767 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/9/BOR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2+(PHASE_OFFSET - PHASE_SIZE) + 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId >= MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) <= address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator <= address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id - 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/9/FVR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/9/FVR/AggregatorProxy.sol new file mode 100644 index 00000000000..4e381017d3d --- /dev/null +++ b/contracts/mutants/AggregatorProxy/9/FVR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) internal Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() public view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() public view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) public onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) public onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) public { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + public + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) public view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + public + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/9/ILR/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/9/ILR/AggregatorProxy.sol new file mode 100644 index 00000000000..11a34b061f0 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/9/ILR/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 63; + uint256 private constant PHASE_SIZE = 15; + uint256 private constant MAX_ID = 1**(PHASE_OFFSET + PHASE_SIZE) - 0; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 1; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 1; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(1)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/9/ORFD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/9/ORFD/AggregatorProxy.sol new file mode 100644 index 00000000000..a092f76f2b4 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/9/ORFD/AggregatorProxy.sol @@ -0,0 +1,308 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/9/RSD/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/9/RSD/AggregatorProxy.sol new file mode 100644 index 00000000000..100b16128c9 --- /dev/null +++ b/contracts/mutants/AggregatorProxy/9/RSD/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + /* return currentPhase.aggregator.latestAnswer(); */ + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + /* return currentPhase.aggregator.latestTimestamp(); */ + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getAnswer(aggregatorRoundId); */ + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) /* return 0; */ + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) /* return 0; */ + + /* return aggregator.getTimestamp(aggregatorRoundId); */ + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + /* return addPhase(phase.id, uint64(phase.aggregator.latestRound())); */ + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorProxy/original/AggregatorProxy.sol b/contracts/mutants/AggregatorProxy/original/AggregatorProxy.sol new file mode 100644 index 00000000000..a67e04294ea --- /dev/null +++ b/contracts/mutants/AggregatorProxy/original/AggregatorProxy.sol @@ -0,0 +1,422 @@ +pragma solidity ^0.7.0; + +import "./Owned.sol"; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; + +/** + * @title A trusted proxy for updating where current answers are read from + * @notice This contract provides a consistent address for the + * CurrentAnwerInterface but delegates where it reads from to the owner, who is + * trusted to update it. + */ +contract AggregatorProxy is AggregatorV2V3Interface, Owned { + struct Phase { + uint16 id; + AggregatorV2V3Interface aggregator; + } + Phase private currentPhase; + AggregatorV2V3Interface public proposedAggregator; + mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; + + uint256 private constant PHASE_OFFSET = 64; + uint256 private constant PHASE_SIZE = 16; + uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; + + constructor(address _aggregator) public Owned() { + setAggregator(_aggregator); + } + + /** + * @notice Reads the current answer from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestAnswer() + public + view + virtual + override + returns (int256 answer) + { + return currentPhase.aggregator.latestAnswer(); + } + + /** + * @notice Reads the last updated height from aggregator delegated to. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestTimestamp() + public + view + virtual + override + returns (uint256 updatedAt) + { + return currentPhase.aggregator.latestTimestamp(); + } + + /** + * @notice get past rounds answers + * @param _roundId the answer number to retrieve the answer for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getAnswer(uint256 _roundId) + public + view + virtual + override + returns (int256 answer) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getAnswer(aggregatorRoundId); + } + + /** + * @notice get block timestamp when an answer was last updated + * @param _roundId the answer number to retrieve the updated timestamp for + * + * @dev #[deprecated] Use getRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended getRoundData + * instead which includes better verification information. + */ + function getTimestamp(uint256 _roundId) + public + view + virtual + override + returns (uint256 updatedAt) + { + if (_roundId > MAX_ID) return 0; + + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; + if (address(aggregator) == address(0)) return 0; + + return aggregator.getTimestamp(aggregatorRoundId); + } + + /** + * @notice get the latest completed round where the answer was updated. This + * ID includes the proxy's phase, to make sure round IDs increase even when + * switching to a newly deployed aggregator. + * + * @dev #[deprecated] Use latestRoundData instead. This does not error if no + * answer has been reached, it will simply return 0. Either wait to point to + * an already answered Aggregator or use the recommended latestRoundData + * instead which includes better verification information. + */ + function latestRound() + public + view + virtual + override + returns (uint256 roundId) + { + Phase memory phase = currentPhase; // cache storage reads + return addPhase(phase.id, uint64(phase.aggregator.latestRound())); + } + + /** + * @notice get data about a round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @param _roundId the requested round ID as presented through the proxy, this + * is made up of the aggregator's round ID with the phase ID encoded in the + * two highest order bytes + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function getRoundData(uint80 _roundId) + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); + + return + addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId); + } + + /** + * @notice get data about the latest round. Consumers are encouraged to check + * that they're receiving fresh data by inspecting the updatedAt and + * answeredInRound return values. + * Note that different underlying implementations of AggregatorV3Interface + * have slightly different semantics for some of the return values. Consumers + * should determine what implementations they expect to receive + * data from and validate that they can properly handle return data from all + * of them. + * @return roundId is the round ID from the aggregator for which the data was + * retrieved combined with an phase to ensure that round IDs get larger as + * time moves forward. + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @dev Note that answer and updatedAt may change between queries. + */ + function latestRoundData() + public + view + virtual + override + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + Phase memory current = currentPhase; // cache storage reads + + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 ansIn + ) = current.aggregator.latestRoundData(); + + return + addPhaseIds( + roundId, + answer, + startedAt, + updatedAt, + ansIn, + current.id + ); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @param _roundId the round ID to retrieve the round data for + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedGetRoundData(uint80 _roundId) + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.getRoundData(_roundId); + } + + /** + * @notice Used if an aggregator contract has been proposed. + * @return roundId is the round ID for which data was retrieved + * @return answer is the answer for the given round + * @return startedAt is the timestamp when the round was started. + * (Only some AggregatorV3Interface implementations return meaningful values) + * @return updatedAt is the timestamp when the round last was updated (i.e. + * answer was last computed) + * @return answeredInRound is the round ID of the round in which the answer + * was computed. + */ + function proposedLatestRoundData() + public + view + virtual + hasProposal() + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) + { + return proposedAggregator.latestRoundData(); + } + + /** + * @notice returns the current phase's aggregator address. + */ + function aggregator() external view returns (address) { + return address(currentPhase.aggregator); + } + + /** + * @notice returns the current phase's ID. + */ + function phaseId() external view returns (uint16) { + return currentPhase.id; + } + + /** + * @notice represents the number of decimals the aggregator responses represent. + */ + function decimals() external view override returns (uint8) { + return currentPhase.aggregator.decimals(); + } + + /** + * @notice the version number representing the type of aggregator the proxy + * points to. + */ + function version() external view override returns (uint256) { + return currentPhase.aggregator.version(); + } + + /** + * @notice returns the description of the aggregator the proxy points to. + */ + function description() external view override returns (string memory) { + return currentPhase.aggregator.description(); + } + + /** + * @notice Allows the owner to propose a new address for the aggregator + * @param _aggregator The new address for the aggregator contract + */ + function proposeAggregator(address _aggregator) external onlyOwner() { + proposedAggregator = AggregatorV2V3Interface(_aggregator); + } + + /** + * @notice Allows the owner to confirm and change the address + * to the proposed aggregator + * @dev Reverts if the given address doesn't match what was previously + * proposed + * @param _aggregator The new address for the aggregator contract + */ + function confirmAggregator(address _aggregator) external onlyOwner() { + require( + _aggregator == address(proposedAggregator), + "Invalid proposed aggregator" + ); + delete proposedAggregator; + setAggregator(_aggregator); + } + + /* + * Internal + */ + + function setAggregator(address _aggregator) internal { + uint16 id = currentPhase.id + 1; + currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); + phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); + } + + function addPhase(uint16 _phase, uint64 _originalId) + internal + view + returns (uint80) + { + return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); + } + + function parseIds(uint256 _roundId) internal view returns (uint16, uint64) { + uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); + uint64 aggregatorRoundId = uint64(_roundId); + + return (phaseId, aggregatorRoundId); + } + + function addPhaseIds( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound, + uint16 phaseId + ) + internal + view + returns ( + uint80, + int256, + uint256, + uint256, + uint80 + ) + { + return ( + addPhase(phaseId, uint64(roundId)), + answer, + startedAt, + updatedAt, + addPhase(phaseId, uint64(answeredInRound)) + ); + } + + /* + * Modifiers + */ + + modifier hasProposal() { + require( + address(proposedAggregator) != address(0), + "No proposed aggregator present" + ); + _; + } +} diff --git a/contracts/mutants/AggregatorV2V3Interface/1/RVS/AggregatorV2V3Interface.sol b/contracts/mutants/AggregatorV2V3Interface/1/RVS/AggregatorV2V3Interface.sol new file mode 100644 index 00000000000..91223a5e40b --- /dev/null +++ b/contracts/mutants/AggregatorV2V3Interface/1/RVS/AggregatorV2V3Interface.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.5.16; + +//import "@chainlink/contracts-0.0.10/src/v0.5/interfaces/AggregatorV2V3Interface.sol"; + +interface AggregatorV2V3Interface { + function latestRound() external view returns (uint256); + + function decimals() external view returns (uint8); + + function getAnswer(uint256 roundId) external view returns (int256); + + function getTimestamp(uint256 roundId) external view returns (uint256); + + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV2V3Interface/1/SCEC/AggregatorV2V3Interface.sol b/contracts/mutants/AggregatorV2V3Interface/1/SCEC/AggregatorV2V3Interface.sol new file mode 100644 index 00000000000..91223a5e40b --- /dev/null +++ b/contracts/mutants/AggregatorV2V3Interface/1/SCEC/AggregatorV2V3Interface.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.5.16; + +//import "@chainlink/contracts-0.0.10/src/v0.5/interfaces/AggregatorV2V3Interface.sol"; + +interface AggregatorV2V3Interface { + function latestRound() external view returns (uint256); + + function decimals() external view returns (uint8); + + function getAnswer(uint256 roundId) external view returns (int256); + + function getTimestamp(uint256 roundId) external view returns (uint256); + + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV2V3Interface/2/RVS/AggregatorV2V3Interface.sol b/contracts/mutants/AggregatorV2V3Interface/2/RVS/AggregatorV2V3Interface.sol new file mode 100644 index 00000000000..02c143895d1 --- /dev/null +++ b/contracts/mutants/AggregatorV2V3Interface/2/RVS/AggregatorV2V3Interface.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.5.16; + +//import "@chainlink/contracts-0.0.10/src/v0.5/interfaces/AggregatorV2V3Interface.sol"; + +interface AggregatorV2V3Interface { + function latestRound() external view returns (uint256); + + function decimals() external view returns (uint8); + + function getAnswer(uint256 roundId) external view returns (int256); + + function getTimestamp(uint256 roundId) external view returns (uint256); + + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); +} diff --git a/contracts/mutants/AggregatorV2V3Interface/2/SCEC/AggregatorV2V3Interface.sol b/contracts/mutants/AggregatorV2V3Interface/2/SCEC/AggregatorV2V3Interface.sol new file mode 100644 index 00000000000..02c143895d1 --- /dev/null +++ b/contracts/mutants/AggregatorV2V3Interface/2/SCEC/AggregatorV2V3Interface.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.5.16; + +//import "@chainlink/contracts-0.0.10/src/v0.5/interfaces/AggregatorV2V3Interface.sol"; + +interface AggregatorV2V3Interface { + function latestRound() external view returns (uint256); + + function decimals() external view returns (uint8); + + function getAnswer(uint256 roundId) external view returns (int256); + + function getTimestamp(uint256 roundId) external view returns (uint256); + + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); +} diff --git a/contracts/mutants/AggregatorV2V3Interface/original/AggregatorV2V3Interface.sol b/contracts/mutants/AggregatorV2V3Interface/original/AggregatorV2V3Interface.sol new file mode 100644 index 00000000000..b933f977543 --- /dev/null +++ b/contracts/mutants/AggregatorV2V3Interface/original/AggregatorV2V3Interface.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.5.16; + +//import "@chainlink/contracts-0.0.10/src/v0.5/interfaces/AggregatorV2V3Interface.sol"; + +interface AggregatorV2V3Interface { + function latestRound() external view returns (uint256); + + function decimals() external view returns (uint8); + + function getAnswer(uint256 roundId) external view returns (int256); + + function getTimestamp(uint256 roundId) external view returns (uint256); + + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV3/1/CCD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/CCD/AggregatorV3.sol new file mode 100644 index 00000000000..9272790dff9 --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/CCD/AggregatorV3.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/DLR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/DLR/AggregatorV3.sol new file mode 100644 index 00000000000..35ae81d54bb --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/DLR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string storage) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/FVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/FVR/AggregatorV3.sol new file mode 100644 index 00000000000..c42e567444d --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/FVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) internal { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..ee728050b98 --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/ORFD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/ORFD/AggregatorV3.sol new file mode 100644 index 00000000000..ea3e10fbe39 --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/ORFD/AggregatorV3.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/RSD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/RSD/AggregatorV3.sol new file mode 100644 index 00000000000..70c79b5afeb --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/RSD/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + /* return dec; */ + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/RVS/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/RVS/AggregatorV3.sol new file mode 100644 index 00000000000..06f1a4663e4 --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/RVS/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, _roundId, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/SCEC/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/SCEC/AggregatorV3.sol new file mode 100644 index 00000000000..06f1a4663e4 --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/SCEC/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, _roundId, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/1/VVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/1/VVR/AggregatorV3.sol new file mode 100644 index 00000000000..5a20a84f63c --- /dev/null +++ b/contracts/mutants/AggregatorV3/1/VVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 public dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/2/FVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/2/FVR/AggregatorV3.sol new file mode 100644 index 00000000000..01a19a93215 --- /dev/null +++ b/contracts/mutants/AggregatorV3/2/FVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) internal { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) external { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/2/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/2/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..34b1644913b --- /dev/null +++ b/contracts/mutants/AggregatorV3/2/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/2/ORFD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/2/ORFD/AggregatorV3.sol new file mode 100644 index 00000000000..2006c891512 --- /dev/null +++ b/contracts/mutants/AggregatorV3/2/ORFD/AggregatorV3.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + + + + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/2/RSD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/2/RSD/AggregatorV3.sol new file mode 100644 index 00000000000..a625ee7ba31 --- /dev/null +++ b/contracts/mutants/AggregatorV3/2/RSD/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + /* return dec; */ + } + + function description() external override virtual view returns (string memory) { + /* return desc; */ + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/2/VVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/2/VVR/AggregatorV3.sol new file mode 100644 index 00000000000..9ba88558afd --- /dev/null +++ b/contracts/mutants/AggregatorV3/2/VVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 public dec; + int256 public price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/3/FVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/3/FVR/AggregatorV3.sol new file mode 100644 index 00000000000..9246d722438 --- /dev/null +++ b/contracts/mutants/AggregatorV3/3/FVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) internal { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) external { + price = _price; + } + + function setDecimals(uint8 _decimals) external { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/3/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/3/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..3aa9d176819 --- /dev/null +++ b/contracts/mutants/AggregatorV3/3/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 0, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/3/ORFD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/3/ORFD/AggregatorV3.sol new file mode 100644 index 00000000000..73c1ead7588 --- /dev/null +++ b/contracts/mutants/AggregatorV3/3/ORFD/AggregatorV3.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + + + + + + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/3/RSD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/3/RSD/AggregatorV3.sol new file mode 100644 index 00000000000..a91c52804b7 --- /dev/null +++ b/contracts/mutants/AggregatorV3/3/RSD/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + /* return dec; */ + } + + function description() external override virtual view returns (string memory) { + /* return desc; */ + } + + function version() external override virtual view returns (uint256) { + /* return vers; */ + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/3/VVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/3/VVR/AggregatorV3.sol new file mode 100644 index 00000000000..7675be2d917 --- /dev/null +++ b/contracts/mutants/AggregatorV3/3/VVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 public dec; + int256 public price; + string public desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/4/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/4/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..ee9d4deb41f --- /dev/null +++ b/contracts/mutants/AggregatorV3/4/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 0, 0); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/4/ORFD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/4/ORFD/AggregatorV3.sol new file mode 100644 index 00000000000..b9b208dcf22 --- /dev/null +++ b/contracts/mutants/AggregatorV3/4/ORFD/AggregatorV3.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + + + + + + + + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/4/RSD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/4/RSD/AggregatorV3.sol new file mode 100644 index 00000000000..cf2942b0acc --- /dev/null +++ b/contracts/mutants/AggregatorV3/4/RSD/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + /* return dec; */ + } + + function description() external override virtual view returns (string memory) { + /* return desc; */ + } + + function version() external override virtual view returns (uint256) { + /* return vers; */ + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + /* return (_roundId, price, 1, 1, 1); */ + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/4/VVR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/4/VVR/AggregatorV3.sol new file mode 100644 index 00000000000..84e07b1e773 --- /dev/null +++ b/contracts/mutants/AggregatorV3/4/VVR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 public dec; + int256 public price; + string public desc = ""; + uint256 public vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/5/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/5/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..2a5a98a48a8 --- /dev/null +++ b/contracts/mutants/AggregatorV3/5/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 0, 0); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/5/ORFD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/5/ORFD/AggregatorV3.sol new file mode 100644 index 00000000000..66bf6ee014b --- /dev/null +++ b/contracts/mutants/AggregatorV3/5/ORFD/AggregatorV3.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + + + + + + + + + + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/5/RSD/AggregatorV3.sol b/contracts/mutants/AggregatorV3/5/RSD/AggregatorV3.sol new file mode 100644 index 00000000000..12bf7b84ed6 --- /dev/null +++ b/contracts/mutants/AggregatorV3/5/RSD/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + /* return dec; */ + } + + function description() external override virtual view returns (string memory) { + /* return desc; */ + } + + function version() external override virtual view returns (uint256) { + /* return vers; */ + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + /* return (_roundId, price, 1, 1, 1); */ + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + /* return (1, price, 1, 1, 1); */ + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/6/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/6/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..708499d2229 --- /dev/null +++ b/contracts/mutants/AggregatorV3/6/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 0, 0); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, price, 0, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/7/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/7/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..dbb8d7ee062 --- /dev/null +++ b/contracts/mutants/AggregatorV3/7/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 0, 0); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, price, 0, 0, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/8/ILR/AggregatorV3.sol b/contracts/mutants/AggregatorV3/8/ILR/AggregatorV3.sol new file mode 100644 index 00000000000..d697184bf81 --- /dev/null +++ b/contracts/mutants/AggregatorV3/8/ILR/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 0; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 0, 0, 0); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, price, 0, 0, 0); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3/original/AggregatorV3.sol b/contracts/mutants/AggregatorV3/original/AggregatorV3.sol new file mode 100644 index 00000000000..d02e28531a1 --- /dev/null +++ b/contracts/mutants/AggregatorV3/original/AggregatorV3.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.6.12; +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract AggregatorV3 is AggregatorV3Interface { + + uint8 dec; + int256 price; + string desc = ""; + uint256 vers = 1; + + constructor(uint8 _decimals) public { + dec = _decimals; + } + + function decimals() external override virtual view returns (uint8) { + return dec; + } + + function description() external override virtual view returns (string memory) { + return desc; + } + + function version() external override virtual view returns (uint256) { + return vers; + } + + function getRoundData(uint80 _roundId) + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (_roundId, price, 1, 1, 1); + } + + function latestRoundData() + external + override + virtual + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, price, 1, 1, 1); + } + + function setPrice(int256 _price) public { + price = _price; + } + + function setDecimals(uint8 _decimals) public { + dec = _decimals; + } +} diff --git a/contracts/mutants/AggregatorV3Interface/1/DLR/AggregatorV3Interface.sol b/contracts/mutants/AggregatorV3Interface/1/DLR/AggregatorV3Interface.sol new file mode 100644 index 00000000000..677c2bb321f --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/1/DLR/AggregatorV3Interface.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.6.12; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string storage); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + uint256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV3Interface/1/DLR/diff_result_difft.json b/contracts/mutants/AggregatorV3Interface/1/DLR/diff_result_difft.json new file mode 100644 index 00000000000..f18cf38729a --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/1/DLR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.14220714569091797, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 6, + "changes": [ + { + "start": 57, + "end": 63, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 6, + "changes": [ + { + "start": 57, + "end": 64, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AggregatorV3Interface/1/RVS/AggregatorV3Interface.sol b/contracts/mutants/AggregatorV3Interface/1/RVS/AggregatorV3Interface.sol new file mode 100644 index 00000000000..b013725a613 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/1/RVS/AggregatorV3Interface.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.6.12; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + uint256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV3Interface/1/RVS/diff_result_difft.json b/contracts/mutants/AggregatorV3Interface/1/RVS/diff_result_difft.json new file mode 100644 index 00000000000..36fcdd3bc7e --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/1/RVS/diff_result_difft.json @@ -0,0 +1,93 @@ +{ + "number_of_changes": 7, + "timing": 0.08774495124816895, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "rhs": { + "line_number": 19, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 29, + "end": 30, + "content": ",", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [] + } + }, + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AggregatorV3Interface/1/SCEC/AggregatorV3Interface.sol b/contracts/mutants/AggregatorV3Interface/1/SCEC/AggregatorV3Interface.sol new file mode 100644 index 00000000000..b013725a613 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/1/SCEC/AggregatorV3Interface.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.6.12; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + uint256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV3Interface/1/SCEC/diff_result_difft.json b/contracts/mutants/AggregatorV3Interface/1/SCEC/diff_result_difft.json new file mode 100644 index 00000000000..9b58b562bf1 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/1/SCEC/diff_result_difft.json @@ -0,0 +1,93 @@ +{ + "number_of_changes": 7, + "timing": 0.0724029541015625, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "rhs": { + "line_number": 19, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 29, + "end": 30, + "content": ",", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AggregatorV3Interface/2/RVS/AggregatorV3Interface.sol b/contracts/mutants/AggregatorV3Interface/2/RVS/AggregatorV3Interface.sol new file mode 100644 index 00000000000..ab719811271 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/2/RVS/AggregatorV3Interface.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.6.12; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 answeredInRound, + uint80 roundId, + uint256 answer, + uint256 startedAt, + uint256 updatedAt + ); +} diff --git a/contracts/mutants/AggregatorV3Interface/2/RVS/diff_result_difft.json b/contracts/mutants/AggregatorV3Interface/2/RVS/diff_result_difft.json new file mode 100644 index 00000000000..2e264ce3847 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/2/RVS/diff_result_difft.json @@ -0,0 +1,156 @@ +{ + "number_of_changes": 13, + "timing": 0.2186121940612793, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 29, + "end": 30, + "content": ",", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [] + } + }, + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "rhs": { + "line_number": 19, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ",", + "highlight": "normal" + } + ] + } + } + ], + [ + { + "rhs": { + "line_number": 28, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 31, + "changes": [ + { + "start": 29, + "end": 30, + "content": ",", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 32, + "changes": [] + } + }, + { + "lhs": { + "line_number": 32, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AggregatorV3Interface/2/SCEC/AggregatorV3Interface.sol b/contracts/mutants/AggregatorV3Interface/2/SCEC/AggregatorV3Interface.sol new file mode 100644 index 00000000000..ab719811271 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/2/SCEC/AggregatorV3Interface.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.6.12; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 answeredInRound, + int256 answer, + uint80 roundId, + uint256 startedAt, + uint256 updatedAt + ); + + function latestRoundData() + external + view + returns ( + uint80 answeredInRound, + uint80 roundId, + uint256 answer, + uint256 startedAt, + uint256 updatedAt + ); +} diff --git a/contracts/mutants/AggregatorV3Interface/2/SCEC/diff_result_difft.json b/contracts/mutants/AggregatorV3Interface/2/SCEC/diff_result_difft.json new file mode 100644 index 00000000000..203a89706ad --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/2/SCEC/diff_result_difft.json @@ -0,0 +1,156 @@ +{ + "number_of_changes": 13, + "timing": 0.10059952735900879, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 17, + "changes": [ + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "rhs": { + "line_number": 19, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 26, + "content": "roundId", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 29, + "end": 30, + "content": ",", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [] + } + } + ], + [ + { + "lhs": { + "line_number": 32, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + } + ] + } + }, + { + "rhs": { + "line_number": 28, + "changes": [ + { + "start": 12, + "end": 18, + "content": "uint80", + "highlight": "normal" + }, + { + "start": 19, + "end": 34, + "content": "answeredInRound", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 31, + "changes": [ + { + "start": 29, + "end": 30, + "content": ",", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 32, + "changes": [] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AggregatorV3Interface/original/AggregatorV3Interface.sol b/contracts/mutants/AggregatorV3Interface/original/AggregatorV3Interface.sol new file mode 100644 index 00000000000..bf710a77797 --- /dev/null +++ b/contracts/mutants/AggregatorV3Interface/original/AggregatorV3Interface.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.6.12; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + uint256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/contracts/mutants/AggregatorV3Mock/1/BOR/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/BOR/AggregatorV3Mock.sol new file mode 100644 index 00000000000..99a719cf367 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/BOR/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + return _answer; + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp + 100; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/1/CCD/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/CCD/AggregatorV3Mock.sol new file mode 100644 index 00000000000..ca1a142351f --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/CCD/AggregatorV3Mock.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + + + function latestAnswer() external view override returns (int256) { + return _answer; + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp - 100; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/1/GVR/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/GVR/AggregatorV3Mock.sol new file mode 100644 index 00000000000..90dbc6ca1e5 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/GVR/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + return _answer; + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.number - 100; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/1/ILR/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/ILR/AggregatorV3Mock.sol new file mode 100644 index 00000000000..004a0c1be00 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/ILR/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + return _answer; + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp - 99; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/1/ORFD/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/ORFD/AggregatorV3Mock.sol new file mode 100644 index 00000000000..8d14831e95d --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/ORFD/AggregatorV3Mock.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp - 100; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/1/RSD/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/RSD/AggregatorV3Mock.sol new file mode 100644 index 00000000000..b71d6076e26 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/RSD/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + /* return _answer; */ + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp - 100; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/1/VVR/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/1/VVR/AggregatorV3Mock.sol new file mode 100644 index 00000000000..786937b7910 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/1/VVR/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 public immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + return _answer; + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp - 100; + } +} diff --git a/contracts/mutants/AggregatorV3Mock/2/ORFD/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/2/ORFD/AggregatorV3Mock.sol new file mode 100644 index 00000000000..7a4f9a07372 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/2/ORFD/AggregatorV3Mock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + + + +} diff --git a/contracts/mutants/AggregatorV3Mock/2/RSD/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/2/RSD/AggregatorV3Mock.sol new file mode 100644 index 00000000000..1c3feb912be --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/2/RSD/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + /* return _answer; */ + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + /* return block.timestamp - 100; */ + } +} diff --git a/contracts/mutants/AggregatorV3Mock/original/AggregatorV3Mock.sol b/contracts/mutants/AggregatorV3Mock/original/AggregatorV3Mock.sol new file mode 100644 index 00000000000..ccf207b2051 --- /dev/null +++ b/contracts/mutants/AggregatorV3Mock/original/AggregatorV3Mock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.6; + +import "../interfaces/AggregatorV3Interface.sol"; + + +contract AggregatorV3Mock is AggregatorV3Interface { + int256 private immutable _answer; + + constructor(int256 answer) { + _answer = answer; + } + + function latestAnswer() external view override returns (int256) { + return _answer; + } + + function latestTimestamp() external view override returns (uint256) { + // solhint-disable-next-line not-rely-on-time + return block.timestamp - 100; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..4263d8140b3 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/CCD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/CCD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..ad949be052d --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/CCD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/DLR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/DLR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..2b66767116d --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/DLR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] storage) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/DOD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/DOD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..f2075207087 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/DOD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/EED/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/EED/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..663cc111764 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/EED/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + /* emit DepositaryAdded(depositary); */ + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/EHC/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/EHC/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..72ea99d048e --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/EHC/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + /* require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); */ + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/FVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/FVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..2498bd5c0b0 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/FVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) internal { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..1c7bb93f3ad --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/LSC/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/LSC/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..97068aba423 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/LSC/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; true; i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/MOD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/MOD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..1c3ff79ce7e --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/MOD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/ORFD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/ORFD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..52ebc4ae266 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/ORFD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/RSD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/RSD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..e39578bb5e6 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/RSD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + /* return depositaries.length; */ + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/SFR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/SFR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..16d0fe51aa9 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/SFR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.add(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/UORD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/UORD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..9928fd02c17 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/UORD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i--) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/1/VVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/1/VVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..8442f1bf283 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/1/VVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 internal maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..701a6e6b5d5 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() <= maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/DLR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/DLR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..bce1c4484a3 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/DLR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] storage) { + address[] storage result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/EED/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/EED/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..c489fba64ea --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/EED/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + /* emit DepositaryAdded(depositary); */ + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + /* emit DepositaryRemoved(depositary); */ + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/EHC/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/EHC/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..2081ffe207b --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/EHC/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + /* require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); */ + /* require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); */ + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/FVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/FVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..686172529e3 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/FVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) internal { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() external view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..2376653db9a --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/LSC/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/LSC/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..23b3ac35b5f --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/LSC/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; true; i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; true; i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/MOD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/MOD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..0d6317395f4 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/MOD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/RSD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/RSD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..4eff8f3083d --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/RSD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + /* return depositaries.length; */ + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + /* return depositariesIndex[depositary] != 0; */ + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/SFR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/SFR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..339c5bd559a --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/SFR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.add(1); + uint256 lastIndex = size().add(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/UORD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/UORD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..93b2feb99bb --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/UORD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i--) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i--) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/2/VVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/2/VVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..d735d1fb256 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/2/VVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 internal maxSize; + + /// @notice Decimals balance. + uint256 internal override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..3e310cb938c --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() <= maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex > 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/EHC/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/EHC/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..3218342667e --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/EHC/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + /* require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); */ + /* require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); */ + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + /* require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); */ + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/FVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/FVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..a21b9677a51 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/FVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) internal { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() external view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) public onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..25ceb8c084f --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/RSD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/RSD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..744cd620be0 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/RSD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + /* return depositaries.length; */ + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + /* return depositariesIndex[depositary] != 0; */ + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + /* return result; */ + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/SFR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/SFR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..9ef3908ff5b --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/SFR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.add(1); + uint256 lastIndex = size().add(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.sub(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/3/VVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/3/VVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..230e86d187a --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/3/VVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 internal maxSize; + + /// @notice Decimals balance. + uint256 internal override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] internal depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/4/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/4/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..07f06a05bc6 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/4/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() <= maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex > 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] > 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/4/FVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/4/FVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..8ed36ccecab --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/4/FVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) internal { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() external view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) public onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) public onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/4/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/4/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..8d63fb48fd4 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/4/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(0); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/4/RSD/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/4/RSD/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..f1d7a4b8d9e --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/4/RSD/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + /* return depositaries.length; */ + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + /* return depositariesIndex[depositary] != 0; */ + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + /* return result; */ + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + /* return result; */ + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/4/SFR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/4/SFR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..40c8658f490 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/4/SFR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.add(1); + uint256 lastIndex = size().add(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.sub(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.add(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/5/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/5/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..08c28d00c20 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/5/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() <= maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex > 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] > 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i <= size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/5/FVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/5/FVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..7eab86fc134 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/5/FVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) internal { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() external view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) public onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) public onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) public view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/5/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/5/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..b10a30eb7e0 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/5/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(0); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(0); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/5/SFR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/5/SFR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..71a05da1a74 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/5/SFR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.add(1); + uint256 lastIndex = size().add(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.sub(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.add(depositaryDecimals); + result = result.sub(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/6/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/6/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..6aec9e3b553 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/6/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() <= maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex > 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] > 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i <= size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i <= size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/6/FVR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/6/FVR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..72a7506c7dd --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/6/FVR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) internal { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() external view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) public onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) public onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) public view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() public view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/6/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/6/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..d9946575cda --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/6/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(0); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(0); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 1; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/6/SFR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/6/SFR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..7bdcedfcda3 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/6/SFR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.add(1); + uint256 lastIndex = size().add(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.sub(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.add(depositaryDecimals); + result = result.sub(depositaryBalance.add(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/7/BOR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/7/BOR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..f560b3a31ec --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/7/BOR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] <= 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() <= maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex > 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] > 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i <= size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i <= size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10+decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/7/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/7/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..54d60258a73 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/7/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(0); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(0); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 1; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 1; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/8/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/8/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..4e4e8b91402 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/8/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(0); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(0); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 1; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 1; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 1; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/9/ILR/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/9/ILR/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..7ae8aa138b1 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/9/ILR/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 1, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 1, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(0); + uint256 lastIndex = size().sub(0); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(0); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 1; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 1; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 1; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(9**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgregateDepositaryBalanceView/original/AgregateDepositaryBalanceView.sol b/contracts/mutants/AgregateDepositaryBalanceView/original/AgregateDepositaryBalanceView.sol new file mode 100644 index 00000000000..8fd34dfd024 --- /dev/null +++ b/contracts/mutants/AgregateDepositaryBalanceView/original/AgregateDepositaryBalanceView.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../utils/OwnablePausable.sol"; +import "./IDepositaryBalanceView.sol"; + +contract AgregateDepositaryBalanceView is IDepositaryBalanceView, OwnablePausable { + using SafeMath for uint256; + + /// @notice The number of depositaries in agregate. + uint256 public maxSize; + + /// @notice Decimals balance. + uint256 public override decimals; + + /// @notice Depositaries in agregate. + IDepositaryBalanceView[] public depositaries; + + /// @dev Depositaries index. + mapping(address => uint256) internal depositariesIndex; + + /// @notice An event thats emitted when an new depositary added to agregate. + event DepositaryAdded(address depositary); + + /// @notice An event thats emitted when an depositary removed from agregate. + event DepositaryRemoved(address depositary); + + /** + * @param _decimals Decimals balance. + * @param _maxSize Max number depositaries in agregate. + */ + constructor(uint256 _decimals, uint256 _maxSize) public { + decimals = _decimals; + maxSize = _maxSize; + } + + /** + * @return Depositaries count of agregate. + */ + function size() public view returns (uint256) { + return depositaries.length; + } + + /** + * @notice Add depositary address to agregate. + * @param depositary Added depositary address. + */ + function addDepositary(address depositary) external onlyOwner { + require(depositariesIndex[depositary] == 0, "AgregateDepositaryBalanceView::addDepositary: depositary already added"); + require(size() < maxSize, "AgregateDepositaryBalanceView::addDepositary: too many depositaries"); + + depositaries.push(IDepositaryBalanceView(depositary)); + depositariesIndex[depositary] = size(); + emit DepositaryAdded(depositary); + } + + /** + * @notice Removed depositary address from agregate. + * @param depositary Removed depositary address. + */ + function removeDepositary(address depositary) external onlyOwner { + uint256 valueIndex = depositariesIndex[depositary]; + require(valueIndex != 0, "AgregateDepositaryBalanceView::removeDepositary: depositary already removed"); + + uint256 toDeleteIndex = valueIndex.sub(1); + uint256 lastIndex = size().sub(1); + IDepositaryBalanceView lastValue = depositaries[lastIndex]; + depositaries[toDeleteIndex] = lastValue; + depositariesIndex[address(lastValue)] = toDeleteIndex.add(1); + depositaries.pop(); + delete depositariesIndex[depositary]; + + emit DepositaryRemoved(depositary); + } + + /** + * @param depositary Target depositary address. + * @return True if target depositary is allowed. + */ + function hasDepositary(address depositary) external view returns (bool) { + return depositariesIndex[depositary] != 0; + } + + /** + * @return Allowed depositaries list. + */ + function allowedDepositaries() external view returns (address[] memory) { + address[] memory result = new address[](size()); + + for (uint256 i = 0; i < size(); i++) { + result[i] = address(depositaries[i]); + } + + return result; + } + + function balance() external view override returns (uint256) { + uint256 result; + + for (uint256 i = 0; i < size(); i++) { + uint256 depositaryBalance = depositaries[i].balance(); + uint256 depositaryDecimals = depositaries[i].decimals(); + uint256 decimalsPower = decimals.sub(depositaryDecimals); + result = result.add(depositaryBalance.mul(10**decimalsPower)); + } + + return result; + } +} diff --git a/contracts/mutants/AgriUTToken/1/AOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/AOR/AgriUTToken.sol new file mode 100644 index 00000000000..c063c86b13a --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/AOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/AVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/AVR/AgriUTToken.sol new file mode 100644 index 00000000000..c063c86b13a --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/AVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..6b0a580b155 --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..a437234df4d --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/CCD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/CCD/AgriUTToken.sol new file mode 100644 index 00000000000..0ddb2d46fcf --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/CCD/AgriUTToken.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/DLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/DLR/AgriUTToken.sol new file mode 100644 index 00000000000..7fef038e18a --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/DLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string storage tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/ECS/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/ECS/AgriUTToken.sol new file mode 100644 index 00000000000..8233aedd8fd --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/ECS/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint8(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/EED/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/EED/AgriUTToken.sol new file mode 100644 index 00000000000..7eeadf3d788 --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/EED/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + /* emit Transfer(_from, _to, _value); */ + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..0b10284eaba --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..edfb012df23 --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/ICM/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/ICM/AgriUTToken.sol new file mode 100644 index 00000000000..5822ea8462e --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/ICM/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] =- _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/ILR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/ILR/AgriUTToken.sol new file mode 100644 index 00000000000..f9bff65ba18 --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/ILR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 17; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/LSC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/LSC/AgriUTToken.sol new file mode 100644 index 00000000000..5822ea8462e --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/LSC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] =- _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..33dd653bdaa --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/ORFD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/ORFD/AgriUTToken.sol new file mode 100644 index 00000000000..69a410d110b --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/ORFD/AgriUTToken.sol @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..5ac19c1c9e2 --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/SKI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/SKI/AgriUTToken.sol new file mode 100644 index 00000000000..5ba15a9139d --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/SKI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = super.allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..03fe8b4d30b --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/UORD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/UORD/AgriUTToken.sol new file mode 100644 index 00000000000..31c27421ee5 --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/UORD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require( _frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/1/VVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/1/VVR/AgriUTToken.sol new file mode 100644 index 00000000000..ae229a3337f --- /dev/null +++ b/contracts/mutants/AgriUTToken/1/VVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string public _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/10/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/10/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..a04bd1f1291 --- /dev/null +++ b/contracts/mutants/AgriUTToken/10/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] - _value > _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] - _value < _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance > amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance + amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/10/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/10/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..6576ebbf95c --- /dev/null +++ b/contracts/mutants/AgriUTToken/10/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + /* require(!_frozenAccounts[_to], "To account frozen"); */ // Check if recipient is frozen + /* require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); */ //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + /* require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); */ + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + /* require(_managedAccounts[sender], "Not a Managed wallet"); */ + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + /* require(owner != address(0), "ERC20: approve from the zero address"); */ + /* require(spender != address(0), "ERC20: approve to the zero address"); */ + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/10/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/10/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..f7988f1393d --- /dev/null +++ b/contracts/mutants/AgriUTToken/10/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) external view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) public + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) public onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) public returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) public { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner public + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/10/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/10/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..0e7557b84cf --- /dev/null +++ b/contracts/mutants/AgriUTToken/10/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + /* return _balances[account]; */ + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + /* return _frozenAccounts[_account]; */ + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + /* return _managedAccounts[_account]; */ + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + /* return true; */ + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + /* return true; */ + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + /* return true; */ + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/10/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/10/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..6cfaed4d0e1 --- /dev/null +++ b/contracts/mutants/AgriUTToken/10/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[tx.origin] = allowed; + emit ManagedAccount(tx.origin, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(tx.origin, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(tx.origin, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, tx.origin); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, tx.origin, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/AOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/AOR/AgriUTToken.sol new file mode 100644 index 00000000000..7ce5f3b70c8 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/AOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] -= _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/AVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/AVR/AgriUTToken.sol new file mode 100644 index 00000000000..7ce5f3b70c8 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/AVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] -= _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..a97a922a8ed --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..604914c5de5 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/DLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/DLR/AgriUTToken.sol new file mode 100644 index 00000000000..304cea0e4fe --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/DLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string storage tokenName, string storage tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/EED/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/EED/AgriUTToken.sol new file mode 100644 index 00000000000..ac9850b0106 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/EED/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + /* emit Transfer(_from, _to, _value); */ + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + /* emit ManagedAccount(msg.sender, allowed); */ + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..e59900b92bf --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..ebbb9c642ae --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/ICM/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/ICM/AgriUTToken.sol new file mode 100644 index 00000000000..0b024e69329 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/ICM/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] =- _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] =- _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/ILR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/ILR/AgriUTToken.sol new file mode 100644 index 00000000000..07fb54ac6fd --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/ILR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 17; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 9 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/LSC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/LSC/AgriUTToken.sol new file mode 100644 index 00000000000..0b024e69329 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/LSC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] =- _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] =- _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..971ab275180 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/ORFD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/ORFD/AgriUTToken.sol new file mode 100644 index 00000000000..153a674e970 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/ORFD/AgriUTToken.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..419f1342d36 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..3f9797396e5 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/UORD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/UORD/AgriUTToken.sol new file mode 100644 index 00000000000..460c1db575d --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/UORD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require( _frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require( _frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/2/VVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/2/VVR/AgriUTToken.sol new file mode 100644 index 00000000000..e38d368d3b5 --- /dev/null +++ b/contracts/mutants/AgriUTToken/2/VVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string public _name; + string public _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/AOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/AOR/AgriUTToken.sol new file mode 100644 index 00000000000..bd8625f2ad7 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/AOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] -= _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] += _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/AVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/AVR/AgriUTToken.sol new file mode 100644 index 00000000000..bd8625f2ad7 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/AVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] -= _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] += _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..29c9c498924 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return false; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..d21615ef8b6 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/DLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/DLR/AgriUTToken.sol new file mode 100644 index 00000000000..dfab46b6d99 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/DLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string storage tokenName, string storage tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string storage) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/EED/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/EED/AgriUTToken.sol new file mode 100644 index 00000000000..40d7a05a528 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/EED/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + /* emit Transfer(_from, _to, _value); */ + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + /* emit ManagedAccount(msg.sender, allowed); */ + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + /* emit Approval(owner, spender, amount); */ + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..c15fc11a508 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..8bb246784c1 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/ICM/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/ICM/AgriUTToken.sol new file mode 100644 index 00000000000..3b2929f6b0c --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/ICM/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] =- _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] =- _value; // Subtract from the targeted balance + _totalSupply =- _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/ILR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/ILR/AgriUTToken.sol new file mode 100644 index 00000000000..e6b3aa00d44 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/ILR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 17; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 9 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(1), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/LSC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/LSC/AgriUTToken.sol new file mode 100644 index 00000000000..3b2929f6b0c --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/LSC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] =- _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] =- _value; // Subtract from the targeted balance + _totalSupply =- _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..088361b3204 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/ORFD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/ORFD/AgriUTToken.sol new file mode 100644 index 00000000000..9d5af46d925 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/ORFD/AgriUTToken.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..0b6363b7140 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..a2e4a5be8a1 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/UORD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/UORD/AgriUTToken.sol new file mode 100644 index 00000000000..b85ef4c72b9 --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/UORD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require( _frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require( _frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require( _frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/3/VVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/3/VVR/AgriUTToken.sol new file mode 100644 index 00000000000..f890b8ba82b --- /dev/null +++ b/contracts/mutants/AgriUTToken/3/VVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string public _name; + string public _symbol; + uint8 public _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/AOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/AOR/AgriUTToken.sol new file mode 100644 index 00000000000..173fa282add --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/AOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] -= _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] += _value; // Subtract from the targeted balance + _totalSupply += _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/AVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/AVR/AgriUTToken.sol new file mode 100644 index 00000000000..173fa282add --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/AVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] += _value; // Subtract from the sender + _balances[_to] -= _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] += _value; // Subtract from the targeted balance + _totalSupply += _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..eb6379fbd48 --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return false; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return false; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..81467131709 --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/DLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/DLR/AgriUTToken.sol new file mode 100644 index 00000000000..7e4bd805b68 --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/DLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string storage tokenName, string storage tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string storage) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string storage) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/EED/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/EED/AgriUTToken.sol new file mode 100644 index 00000000000..12852a6297c --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/EED/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + /* emit Transfer(_from, _to, _value); */ + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + /* emit ManagedAccount(msg.sender, allowed); */ + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + /* emit Approval(owner, spender, amount); */ + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + /* emit FrozenFunds(target, freeze); */ + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..8e04351abcd --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..8a5dcdf2b50 --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/ILR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/ILR/AgriUTToken.sol new file mode 100644 index 00000000000..5fbd9ecef8f --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/ILR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 17; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 9 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(1), "ERC20: approve from the zero address"); + require(spender != address(1), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..a8074622e0b --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external onlyOwner returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/ORFD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/ORFD/AgriUTToken.sol new file mode 100644 index 00000000000..bf1d7b7b563 --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/ORFD/AgriUTToken.sol @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..c2596d1857a --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..5a29e3f2ce1 --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/4/VVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/4/VVR/AgriUTToken.sol new file mode 100644 index 00000000000..2f34e7a376b --- /dev/null +++ b/contracts/mutants/AgriUTToken/4/VVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string public _name; + string public _symbol; + uint8 public _decimals = 18; + uint256 public _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..6787f72abe4 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return false; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return false; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return false; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..9df73e9024d --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] - _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/EED/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/EED/AgriUTToken.sol new file mode 100644 index 00000000000..7fde8105b81 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/EED/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + /* emit Transfer(_from, _to, _value); */ + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + /* emit ManagedAccount(msg.sender, allowed); */ + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + /* emit Approval(owner, spender, amount); */ + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + /* emit FrozenFunds(target, freeze); */ + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + /* emit Burn(_address, _value); */ + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..a011e85ed84 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + /* require(!_frozenAccounts[_to], "To account frozen"); */ // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..1dcc74ae33a --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) external view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/ILR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/ILR/AgriUTToken.sol new file mode 100644 index 00000000000..1ee36132293 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/ILR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 17; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 9 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(1), "ERC20: approve from the zero address"); + require(spender != address(1), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(1), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..f90d72c9ec7 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external onlyOwner returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override onlyOwner returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/ORFD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/ORFD/AgriUTToken.sol new file mode 100644 index 00000000000..0b5512257c1 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/ORFD/AgriUTToken.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..9305a887948 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + /* return _balances[account]; */ + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/5/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/5/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..1f8e7adc5f6 --- /dev/null +++ b/contracts/mutants/AgriUTToken/5/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[tx.origin] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..d240ee6b82d --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return false; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return false; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return false; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return false; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..092d5ae5da0 --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] - _value > _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..901f6733732 --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + /* require(!_frozenAccounts[_to], "To account frozen"); */ // Check if recipient is frozen + /* require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); */ //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..3e676257110 --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) external view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) public + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..8b2530c5243 --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external onlyOwner returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override onlyOwner returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal onlyOwner { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/ORFD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/ORFD/AgriUTToken.sol new file mode 100644 index 00000000000..f77ee37e663 --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/ORFD/AgriUTToken.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..faff839115c --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + /* return _balances[account]; */ + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + /* return _frozenAccounts[_account]; */ + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/6/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/6/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..3152bfc363a --- /dev/null +++ b/contracts/mutants/AgriUTToken/6/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[tx.origin] = allowed; + emit ManagedAccount(tx.origin, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..dcfacb60ce4 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return false; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return false; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return false; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return false; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return false; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..d61f8006894 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] - _value > _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] - _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..6053e336802 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + /* require(!_frozenAccounts[_to], "To account frozen"); */ // Check if recipient is frozen + /* require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); */ //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + /* require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); */ + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..e32d7da1e48 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) external view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) public + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) public onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..74b30ccc5a5 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external onlyOwner returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override onlyOwner returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal onlyOwner { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external onlyOwner returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..dd5c8e0d249 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + /* return _balances[account]; */ + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + /* return _frozenAccounts[_account]; */ + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + /* return _managedAccounts[_account]; */ + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/7/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/7/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..9b71f0a3af7 --- /dev/null +++ b/contracts/mutants/AgriUTToken/7/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[tx.origin] = allowed; + emit ManagedAccount(tx.origin, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(tx.origin, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/BLR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/BLR/AgriUTToken.sol new file mode 100644 index 00000000000..9f2f0d24f30 --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/BLR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return false; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return false; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return false; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return false; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return false; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return false; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return false; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..3c909bcd3be --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] - _value > _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] - _value < _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..4a7e19756a3 --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + /* require(!_frozenAccounts[_to], "To account frozen"); */ // Check if recipient is frozen + /* require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); */ //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + /* require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); */ + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + /* require(_managedAccounts[sender], "Not a Managed wallet"); */ + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..1f3df4b6b22 --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) external view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) public + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) public onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) public returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..f66df83c262 --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external onlyOwner returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override onlyOwner returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal onlyOwner { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external onlyOwner returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external onlyOwner returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..4fbdd4e2cd0 --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + /* return _balances[account]; */ + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + /* return _frozenAccounts[_account]; */ + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + /* return _managedAccounts[_account]; */ + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + /* return true; */ + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/8/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/8/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..704ca432f24 --- /dev/null +++ b/contracts/mutants/AgriUTToken/8/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[tx.origin] = allowed; + emit ManagedAccount(tx.origin, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(tx.origin, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(tx.origin, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/9/BOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/9/BOR/AgriUTToken.sol new file mode 100644 index 00000000000..d9a35a4f721 --- /dev/null +++ b/contracts/mutants/AgriUTToken/9/BOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply + 10 + uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to > address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] > _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] - _value > _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] - _value < _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance > amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/9/EHC/AgriUTToken.sol b/contracts/mutants/AgriUTToken/9/EHC/AgriUTToken.sol new file mode 100644 index 00000000000..d4ab915c5fe --- /dev/null +++ b/contracts/mutants/AgriUTToken/9/EHC/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + /* require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); */ // Prevent transfer to 0x0 address. Use burn() instead + /* require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); */ // Check if the sender has enough + /* require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); */ // Check for overflows + /* require(!_frozenAccounts[_from], "From account frozen"); */ // Check if sender is frozen + /* require(!_frozenAccounts[_to], "To account frozen"); */ // Check if recipient is frozen + /* require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); */ //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + /* require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); */ + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + /* require(_managedAccounts[sender], "Not a Managed wallet"); */ + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + /* require(owner != address(0), "ERC20: approve from the zero address"); */ + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/9/FVR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/9/FVR/AgriUTToken.sol new file mode 100644 index 00000000000..fb061d9972a --- /dev/null +++ b/contracts/mutants/AgriUTToken/9/FVR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() external view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() external view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() external view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) external view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) external view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) public + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) public onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) public returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) public { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/9/MOI/AgriUTToken.sol b/contracts/mutants/AgriUTToken/9/MOI/AgriUTToken.sol new file mode 100644 index 00000000000..315aa1ca31b --- /dev/null +++ b/contracts/mutants/AgriUTToken/9/MOI/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + onlyOwner { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override onlyOwner returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override onlyOwner returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external onlyOwner returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override onlyOwner returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal onlyOwner { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external onlyOwner returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external onlyOwner returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + onlyOwner { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/9/RSD/AgriUTToken.sol b/contracts/mutants/AgriUTToken/9/RSD/AgriUTToken.sol new file mode 100644 index 00000000000..dc7d5d8914d --- /dev/null +++ b/contracts/mutants/AgriUTToken/9/RSD/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + /* return _decimals; */ + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + /* return _totalSupply; */ + } + + /* Name of Token */ + function name() public view returns (string memory) + { + /* return _name; */ + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + /* return _symbol; */ + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + /* return _balances[account]; */ + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + /* return _frozenAccounts[_account]; */ + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + /* return _managedAccounts[_account]; */ + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + /* return true; */ + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + /* return true; */ + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/9/TOR/AgriUTToken.sol b/contracts/mutants/AgriUTToken/9/TOR/AgriUTToken.sol new file mode 100644 index 00000000000..b4d23d12b04 --- /dev/null +++ b/contracts/mutants/AgriUTToken/9/TOR/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[tx.origin] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(tx.origin, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][tx.origin]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, tx.origin, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[tx.origin] = allowed; + emit ManagedAccount(tx.origin, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(tx.origin, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(tx.origin, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, tx.origin); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AgriUTToken/original/AgriUTToken.sol b/contracts/mutants/AgriUTToken/original/AgriUTToken.sol new file mode 100644 index 00000000000..aa156f2c3b0 --- /dev/null +++ b/contracts/mutants/AgriUTToken/original/AgriUTToken.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// SWC-103-Floating Pragma: L3 +pragma solidity =0.8.6; +import "./OwnableToken.sol"; +import "./ERC20Interface.sol"; + +contract AgriUTToken is OwnableToken, ERC20Interface +{ + string private _name; + string private _symbol; + uint8 private _decimals = 18; + uint256 private _totalSupply; + + mapping(address => mapping(address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => bool) private _frozenAccounts; + mapping(address => bool) private _managedAccounts; + + event FrozenFunds(address indexed target, bool frozen); + event Burn(address indexed from, uint256 value); + event ManagedAccount(address indexed target, bool managed); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + constructor( uint256 initialSupply, string memory tokenName, string memory tokenSymbol) + { + _totalSupply = initialSupply * 10 ** uint256(_decimals); // Update total supply with the decimal amount + _balances[msg.sender] = _totalSupply; // Give the creator all initial tokens + _name = tokenName; // Set the name for display purposes + _symbol = tokenSymbol; // Set the symbol for display purposes + } + + /* returns number of decimals */ + function decimals() public view returns (uint8) + { + return _decimals; + } + + /* returns total supply */ + function totalSupply() public override view returns (uint256) + { + return _totalSupply; + } + + /* Name of Token */ + function name() public view returns (string memory) + { + return _name; + } + + /* Symbol of Token */ + function symbol() public view returns (string memory) + { + return _symbol; + } + + /* returns Balance of given account */ + function balanceOf(address account) public override view returns (uint256) + { + return _balances[account]; + } + + /* returns frozen state of given account */ + function frozenAccount(address _account) public view returns (bool frozen) + { + return _frozenAccounts[_account]; + } + + /* returns flag if given account is managed */ + function managedAccount(address _account) public view returns (bool managed) + { + return _managedAccounts[_account]; + } + + /* Internal transfer, only can be called by this contract */ + function _transfer(address _from, address _to, uint256 _value) internal + { + require (_to != address(0x0), "ERC20: No transfer to 0x0 address"); // Prevent transfer to 0x0 address. Use burn() instead + require (_balances[_from] >= _value, "ERC20: Insufficent tokens"); // Check if the sender has enough + require (_balances[_to] + _value >= _balances[_to], "ERC20:Invalid amount"); // Check for overflows + require(!_frozenAccounts[_from], "From account frozen"); // Check if sender is frozen + require(!_frozenAccounts[_to], "To account frozen"); // Check if recipient is frozen + require (_balances[_to] + _value <= _totalSupply, "ERC20: Total supply exceeded"); //Ensure allocate more than total supply to 1 account + _balances[_from] -= _value; // Subtract from the sender + _balances[_to] += _value; // Add the same to the recipient + emit Transfer(_from, _to, _value); + } + + /** + * Transfer tokens + * Send _value tokens to _to from your account + * @param _to The address of the recipient + * @param _value the amount to send + */ + function transfer(address _to, uint256 _value) public override returns (bool success) + { + _transfer(msg.sender, _to, _value); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) + { + uint256 currentAllowance = _allowances[sender][msg.sender]; + require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); + unchecked { + _approve(sender, msg.sender, currentAllowance - amount); + } + _transfer(sender, recipient, amount); + return true; + } + + /** + * Transfer tokens from 1 account to another + * Send _value tokens to _to from specified account + * @param sender The address of the sender + * @param recipient The address of the recipient + * @param amount the amount to send + */ + function transferFromGivenApproval( address sender, address recipient, uint256 amount) external onlyOwner returns (bool) + { + require(_managedAccounts[sender], "Not a Managed wallet"); + _transfer(sender, recipient, amount); + return true; + } + + /** + * Approves owner to be able to transfer on users behalf + * @param allowed flag to indicate if allowed to manage + */ + function approveOwnerToManage(bool allowed) external returns (bool) + { + _managedAccounts[msg.sender] = allowed; + emit ManagedAccount(msg.sender, allowed); + return true; + } + + /** + * Approve address to spend token on behalf of caller + * @param spender account to grant permission + * @param amount which spender can access + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) + { + _approve(msg.sender, spender, amount); + return true; + } + + function _approve( address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /* + * Returns allowance + * @param tokenOwner account owner + * @param spender account allowed to use tokens + */ + function allowance(address tokenOwner, address spender) public view override returns (uint256 remaining) + { + return _allowances[tokenOwner][spender]; + } + + /// @notice Prevent / allow target from sending and receiving tokens + /// @param target Address to be frozen + /// @param freeze either to freeze it or not + function freezeAccount(address target, bool freeze) onlyOwner external + { + require(target != owner(), "Cannot freeze the owner account"); + _frozenAccounts[target] = freeze; + emit FrozenFunds(target, freeze); + } + + /** + * Destroy tokens + * Remove _value tokens from the system irreversibly + * @param _value the amount of money to burn + */ + function burn(uint256 _value) external returns (bool success) + { + _burn(msg.sender, _value); + return true; + } + + /** + * Burn With Approval + * Burns tokens from a pre-approved address + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnWithApproval(address _from, uint256 _value) external onlyOwner returns (bool success) + { + require(_managedAccounts[_from], "Not a Managed wallet"); + _burn(_from, _value); + return true; + } + + /** + * Destroy tokens from other account + * Remove _value tokens from the system irreversibly on behalf of _from + * @param _from the address of the sender + * @param _value the amount of money to burn + */ + function burnFrom(address _from, uint256 _value) external returns (bool success) + { + uint256 currentAllowance = allowance(_from, msg.sender); + require(currentAllowance >= _value, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(_from, msg.sender, currentAllowance - _value); + } + _burn(_from, _value); + return true; + } + + function _burn(address _address, uint256 _value) internal + { + require(_address != address(0), "ERC20: burn from the zero address"); + require(_balances[_address] >= _value, "ERC20: burn amount exceeds balance"); // Check if the targeted balance is enough + require(!_frozenAccounts[_address], "Account is frozen"); + _balances[_address] -= _value; // Subtract from the targeted balance + _totalSupply -= _value; // Update totalSupply + emit Burn(_address, _value); + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/BLR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/BLR/AirdropAVAX.sol new file mode 100644 index 00000000000..a9253af626d --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/BLR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = false; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/BLR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/BLR/diff_result_difft.json new file mode 100644 index 00000000000..7491565fdd3 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/BLR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.12500929832458496, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 44, + "changes": [ + { + "start": 33, + "end": 37, + "content": "true", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 44, + "changes": [ + { + "start": 33, + "end": 38, + "content": "false", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/BOR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/BOR/AirdropAVAX.sol new file mode 100644 index 00000000000..5c0bede6289 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/BOR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/BOR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/BOR/diff_result_difft.json new file mode 100644 index 00000000000..e51119a89dd --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/BOR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.15009260177612305, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 23, + "end": 24, + "content": ">", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/CCD/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/CCD/AirdropAVAX.sol new file mode 100644 index 00000000000..e92f3e4c57f --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/CCD/AirdropAVAX.sol @@ -0,0 +1,64 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/CCD/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/CCD/diff_result_difft.json new file mode 100644 index 00000000000..67e984a924a --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/CCD/diff_result_difft.json @@ -0,0 +1,178 @@ +{ + "number_of_changes": 23, + "timing": 0.13043618202209473, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 13, + "content": "admin", + "highlight": "normal" + }, + { + "start": 14, + "end": 15, + "content": "=", + "highlight": "normal" + }, + { + "start": 16, + "end": 22, + "content": "IAdmin", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 23, + "end": 29, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 23, + "changes": [ + { + "start": 4, + "end": 5, + "content": "}", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 4, + "end": 15, + "content": "constructor", + "highlight": "type" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 23, + "content": "address", + "highlight": "normal" + }, + { + "start": 24, + "end": 30, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 32, + "end": 38, + "content": "public", + "highlight": "keyword" + }, + { + "start": 39, + "end": 40, + "content": "{", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 22, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 26, + "end": 33, + "content": "address", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 37, + "content": ")", + "highlight": "delimiter" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/DLR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/DLR/AirdropAVAX.sol new file mode 100644 index 00000000000..e91ccee2354 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/DLR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes storage signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/DLR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/DLR/diff_result_difft.json new file mode 100644 index 00000000000..bdff2fa409f --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/DLR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.20522499084472656, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 34, + "end": 40, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 34, + "end": 41, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/EED/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/EED/AirdropAVAX.sol new file mode 100644 index 00000000000..d8a4c35902a --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/EED/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + /* emit SentAVAX(beneficiary, amount); */ + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/EED/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/EED/diff_result_difft.json new file mode 100644 index 00000000000..e6df3737e62 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/EED/diff_result_difft.json @@ -0,0 +1,68 @@ +{ + "number_of_changes": 7, + "timing": 0.22564005851745605, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 12, + "content": "emit", + "highlight": "keyword" + }, + { + "start": 13, + "end": 21, + "content": "SentAVAX", + "highlight": "type" + }, + { + "start": 21, + "end": 22, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 22, + "end": 33, + "content": "beneficiary", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": ",", + "highlight": "normal" + }, + { + "start": 35, + "end": 41, + "content": "amount", + "highlight": "normal" + }, + { + "start": 41, + "end": 42, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 49, + "content": "/* emit SentAVAX(beneficiary, amount); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/EHC/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/EHC/AirdropAVAX.sol new file mode 100644 index 00000000000..2d00cd6394c --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/EHC/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/EHC/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/EHC/diff_result_difft.json new file mode 100644 index 00000000000..003bf230a94 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/EHC/diff_result_difft.json @@ -0,0 +1,80 @@ +{ + "number_of_changes": 9, + "timing": 0.20591998100280762, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 22, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 26, + "end": 33, + "content": "address", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 37, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 44, + "content": "/* require(_admin != address(0)); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/ETR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/ETR/AirdropAVAX.sol new file mode 100644 index 00000000000..99f8b40c680 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/ETR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.delegatecall(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/ETR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/ETR/diff_result_difft.json new file mode 100644 index 00000000000..fa0c07a5190 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/ETR/diff_result_difft.json @@ -0,0 +1,62 @@ +{ + "number_of_changes": 6, + "timing": 0.30678582191467285, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 28, + "changes": [ + { + "start": 30, + "end": 34, + "content": "call", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "{", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 40, + "content": "value", + "highlight": "normal" + }, + { + "start": 40, + "end": 41, + "content": ":", + "highlight": "normal" + }, + { + "start": 42, + "end": 47, + "content": "value", + "highlight": "normal" + }, + { + "start": 47, + "end": 48, + "content": "}", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 28, + "changes": [ + { + "start": 30, + "end": 42, + "content": "delegatecall", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/FVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/FVR/AirdropAVAX.sol new file mode 100644 index 00000000000..8edd2039458 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/FVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/FVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/FVR/diff_result_difft.json new file mode 100644 index 00000000000..b92cd6b80ae --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/FVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.14873051643371582, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 38, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 40, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/ILR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/ILR/AirdropAVAX.sol new file mode 100644 index 00000000000..afac0578025 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/ILR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/ILR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/ILR/diff_result_difft.json new file mode 100644 index 00000000000..963a2f1d877 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/ILR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.12569546699523926, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 34, + "end": 35, + "content": "1", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/MCR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/MCR/AirdropAVAX.sol new file mode 100644 index 00000000000..cd370757443 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/MCR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = sha256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/MCR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/MCR/diff_result_difft.json new file mode 100644 index 00000000000..27d1cae2a9d --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/MCR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.06839513778686523, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 55, + "changes": [ + { + "start": 23, + "end": 32, + "content": "keccak256", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 55, + "changes": [ + { + "start": 23, + "end": 29, + "content": "sha256", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/RSD/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/RSD/AirdropAVAX.sol new file mode 100644 index 00000000000..aa2fe1b7093 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/RSD/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + /* return messageHash.recover(signature); */ + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/RSD/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/RSD/diff_result_difft.json new file mode 100644 index 00000000000..477de981b53 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/RSD/diff_result_difft.json @@ -0,0 +1,68 @@ +{ + "number_of_changes": 7, + "timing": 0.1703202724456787, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 57, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 26, + "content": "messageHash", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ".", + "highlight": "normal" + }, + { + "start": 27, + "end": 34, + "content": "recover", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 44, + "content": "signature", + "highlight": "normal" + }, + { + "start": 44, + "end": 45, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 57, + "changes": [ + { + "start": 8, + "end": 52, + "content": "/* return messageHash.recover(signature); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/SFR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/SFR/AirdropAVAX.sol new file mode 100644 index 00000000000..ddb3968fb41 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/SFR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.sub(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/SFR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/SFR/diff_result_difft.json new file mode 100644 index 00000000000..e331bdd0cce --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/SFR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.16522431373596191, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 48, + "changes": [ + { + "start": 52, + "end": 55, + "content": "add", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 48, + "changes": [ + { + "start": 52, + "end": 55, + "content": "sub", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/TOR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/TOR/AirdropAVAX.sol new file mode 100644 index 00000000000..4d446a817d2 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/TOR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(tx.origin == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/TOR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/TOR/diff_result_difft.json new file mode 100644 index 00000000000..dd9d0a647ce --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/TOR/diff_result_difft.json @@ -0,0 +1,44 @@ +{ + "number_of_changes": 2, + "timing": 0.1257483959197998, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 16, + "end": 18, + "content": "tx", + "highlight": "normal" + }, + { + "start": 19, + "end": 25, + "content": "origin", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/UORD/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/UORD/AirdropAVAX.sol new file mode 100644 index 00000000000..d78488d621e --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/UORD/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require( wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/UORD/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/UORD/diff_result_difft.json new file mode 100644 index 00000000000..91676cc2c9e --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/UORD/diff_result_difft.json @@ -0,0 +1,25 @@ +{ + "number_of_changes": 1, + "timing": 0.07064247131347656, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 16, + "end": 17, + "content": "!", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/1/VVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/1/VVR/AirdropAVAX.sol new file mode 100644 index 00000000000..f79dbf46fb8 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/VVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin internal admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/1/VVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/1/VVR/diff_result_difft.json new file mode 100644 index 00000000000..21af6e3ac91 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/1/VVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.24512720108032227, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 12, + "changes": [ + { + "start": 11, + "end": 17, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 12, + "changes": [ + { + "start": 11, + "end": 19, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/BOR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/BOR/AirdropAVAX.sol new file mode 100644 index 00000000000..6f4a23ee674 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/BOR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender <= tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/BOR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/BOR/diff_result_difft.json new file mode 100644 index 00000000000..82fb977b8ee --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/BOR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.3166325092315674, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 23, + "end": 24, + "content": ">", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 27, + "end": 29, + "content": "<=", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/DLR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/DLR/AirdropAVAX.sol new file mode 100644 index 00000000000..6aa49f59996 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/DLR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes storage signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes storage signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/DLR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/DLR/diff_result_difft.json new file mode 100644 index 00000000000..fff52f83cc3 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/DLR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.20548391342163086, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 34, + "end": 40, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 34, + "end": 41, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 54, + "changes": [ + { + "start": 29, + "end": 35, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 54, + "changes": [ + { + "start": 29, + "end": 36, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/EHC/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/EHC/AirdropAVAX.sol new file mode 100644 index 00000000000..c496020a368 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/EHC/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + /* require(success, "AVAX transfer failed."); */ + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/EHC/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/EHC/diff_result_difft.json new file mode 100644 index 00000000000..37c9ca8cbaf --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/EHC/diff_result_difft.json @@ -0,0 +1,136 @@ +{ + "number_of_changes": 15, + "timing": 0.23905158042907715, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 22, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 26, + "end": 33, + "content": "address", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 37, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 44, + "content": "/* require(_admin != address(0)); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 23, + "content": "success", + "highlight": "normal" + }, + { + "start": 23, + "end": 24, + "content": ",", + "highlight": "normal" + }, + { + "start": 25, + "end": 48, + "content": "\"AVAX transfer failed.\"", + "highlight": "string" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* require(success, \"AVAX transfer failed.\"); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/FVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/FVR/AirdropAVAX.sol new file mode 100644 index 00000000000..392542375fa --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/FVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) public { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/FVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/FVR/diff_result_difft.json new file mode 100644 index 00000000000..1f46a530e4b --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/FVR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.2603468894958496, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 38, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 40, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 65, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 63, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/ILR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/ILR/AirdropAVAX.sol new file mode 100644 index 00000000000..033a23a7134 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/ILR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(1)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/ILR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/ILR/diff_result_difft.json new file mode 100644 index 00000000000..ee73b52ad28 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/ILR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.190277099609375, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 34, + "end": 35, + "content": "1", + "highlight": "normal" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 28, + "changes": [ + { + "start": 59, + "end": 60, + "content": "0", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 28, + "changes": [ + { + "start": 59, + "end": 60, + "content": "1", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/RSD/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/RSD/AirdropAVAX.sol new file mode 100644 index 00000000000..25d03bbf491 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/RSD/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + /* return messageHash.recover(signature); */ + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + /* return admin.isAdmin(getSigner(signature, beneficiary, amount)); */ + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/RSD/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/RSD/diff_result_difft.json new file mode 100644 index 00000000000..3387a025f21 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/RSD/diff_result_difft.json @@ -0,0 +1,172 @@ +{ + "number_of_changes": 21, + "timing": 0.08831501007080078, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 57, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 26, + "content": "messageHash", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ".", + "highlight": "normal" + }, + { + "start": 27, + "end": 34, + "content": "recover", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 44, + "content": "signature", + "highlight": "normal" + }, + { + "start": 44, + "end": 45, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 57, + "changes": [ + { + "start": 8, + "end": 52, + "content": "/* return messageHash.recover(signature); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 62, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 20, + "content": "admin", + "highlight": "normal" + }, + { + "start": 20, + "end": 21, + "content": ".", + "highlight": "normal" + }, + { + "start": 21, + "end": 28, + "content": "isAdmin", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 38, + "content": "getSigner", + "highlight": "normal" + }, + { + "start": 38, + "end": 39, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 39, + "end": 48, + "content": "signature", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ",", + "highlight": "normal" + }, + { + "start": 50, + "end": 61, + "content": "beneficiary", + "highlight": "normal" + }, + { + "start": 61, + "end": 62, + "content": ",", + "highlight": "normal" + }, + { + "start": 63, + "end": 69, + "content": "amount", + "highlight": "normal" + }, + { + "start": 69, + "end": 70, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 70, + "end": 71, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 62, + "changes": [ + { + "start": 8, + "end": 78, + "content": "/* return admin.isAdmin(getSigner(signature, beneficiary, amount)); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/TOR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/TOR/AirdropAVAX.sol new file mode 100644 index 00000000000..ee96aaa63e3 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/TOR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(tx.origin == msg.sender, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/TOR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/TOR/diff_result_difft.json new file mode 100644 index 00000000000..24b9f02b092 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/TOR/diff_result_difft.json @@ -0,0 +1,68 @@ +{ + "number_of_changes": 7, + "timing": 0.34722304344177246, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": ".", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + }, + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 26, + "end": 28, + "content": "==", + "highlight": "keyword" + }, + { + "start": 29, + "end": 32, + "content": "msg", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "sender", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/2/VVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/2/VVR/AirdropAVAX.sol new file mode 100644 index 00000000000..c27f50d8a93 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/VVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin internal admin; + uint256 internal totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/2/VVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/2/VVR/diff_result_difft.json new file mode 100644 index 00000000000..f3d08afdb20 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/2/VVR/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 2, + "timing": 0.19044089317321777, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 12, + "changes": [ + { + "start": 11, + "end": 17, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 12, + "changes": [ + { + "start": 11, + "end": 19, + "content": "internal", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 13, + "changes": [ + { + "start": 12, + "end": 18, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 13, + "changes": [ + { + "start": 12, + "end": 20, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/3/DLR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/3/DLR/AirdropAVAX.sol new file mode 100644 index 00000000000..4ae9a3af25a --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/DLR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes storage signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes storage signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes storage signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/3/DLR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/3/DLR/diff_result_difft.json new file mode 100644 index 00000000000..d9227a64cca --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/DLR/diff_result_difft.json @@ -0,0 +1,84 @@ +{ + "number_of_changes": 3, + "timing": 0.11465787887573242, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 34, + "end": 40, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 34, + "end": 41, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 54, + "changes": [ + { + "start": 29, + "end": 35, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 54, + "changes": [ + { + "start": 29, + "end": 36, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 61, + "changes": [ + { + "start": 34, + "end": 40, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 61, + "changes": [ + { + "start": 34, + "end": 41, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/3/EHC/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/3/EHC/AirdropAVAX.sol new file mode 100644 index 00000000000..67a781c8be1 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/EHC/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + /* require(success, "AVAX transfer failed."); */ + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/3/EHC/diff_result_difft.json b/contracts/mutants/AirdropAVAX/3/EHC/diff_result_difft.json new file mode 100644 index 00000000000..6253da67a06 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/EHC/diff_result_difft.json @@ -0,0 +1,228 @@ +{ + "number_of_changes": 27, + "timing": 0.15054059028625488, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 22, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 26, + "end": 33, + "content": "address", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 37, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 44, + "content": "/* require(_admin != address(0)); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 23, + "content": "success", + "highlight": "normal" + }, + { + "start": 23, + "end": 24, + "content": ",", + "highlight": "normal" + }, + { + "start": 25, + "end": 48, + "content": "\"AVAX transfer failed.\"", + "highlight": "string" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* require(success, \"AVAX transfer failed.\"); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": ".", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + }, + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + }, + { + "start": 30, + "end": 32, + "content": "tx", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "origin", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": ",", + "highlight": "normal" + }, + { + "start": 41, + "end": 84, + "content": "\"Require that message sender is tx-origin.\"", + "highlight": "string" + }, + { + "start": 84, + "end": 85, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 8, + "end": 92, + "content": "/* require(msg.sender == tx.origin, \"Require that message sender is tx-origin.\"); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/3/FVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/3/FVR/AirdropAVAX.sol new file mode 100644 index 00000000000..bb799771240 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/FVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) public { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) external { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/3/FVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/3/FVR/diff_result_difft.json new file mode 100644 index 00000000000..f1fce7505c8 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/FVR/diff_result_difft.json @@ -0,0 +1,84 @@ +{ + "number_of_changes": 3, + "timing": 0.2100839614868164, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 38, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 40, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 65, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 63, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 68, + "end": 74, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 68, + "end": 76, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/3/TOR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/3/TOR/AirdropAVAX.sol new file mode 100644 index 00000000000..cf1381cb74e --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/TOR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(tx.origin == msg.sender, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = tx.origin; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/3/TOR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/3/TOR/diff_result_difft.json new file mode 100644 index 00000000000..14a9a9792a3 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/3/TOR/diff_result_difft.json @@ -0,0 +1,104 @@ +{ + "number_of_changes": 9, + "timing": 0.13527679443359375, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 30, + "end": 33, + "content": "msg", + "highlight": "normal" + }, + { + "start": 34, + "end": 40, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 30, + "end": 32, + "content": "tx", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "origin", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": ".", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + }, + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 26, + "end": 28, + "content": "==", + "highlight": "keyword" + }, + { + "start": 29, + "end": 32, + "content": "msg", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "sender", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/4/EHC/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/4/EHC/AirdropAVAX.sol new file mode 100644 index 00000000000..405a8bdf6f4 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/4/EHC/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + /* require(success, "AVAX transfer failed."); */ + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + /* require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); */ + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/4/EHC/diff_result_difft.json b/contracts/mutants/AirdropAVAX/4/EHC/diff_result_difft.json new file mode 100644 index 00000000000..c4e9cfeab13 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/4/EHC/diff_result_difft.json @@ -0,0 +1,324 @@ +{ + "number_of_changes": 40, + "timing": 0.20271539688110352, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 22, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 26, + "end": 33, + "content": "address", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 37, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 44, + "content": "/* require(_admin != address(0)); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 23, + "content": "success", + "highlight": "normal" + }, + { + "start": 23, + "end": 24, + "content": ",", + "highlight": "normal" + }, + { + "start": 25, + "end": 48, + "content": "\"AVAX transfer failed.\"", + "highlight": "string" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* require(success, \"AVAX transfer failed.\"); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": ".", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + }, + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + }, + { + "start": 30, + "end": 32, + "content": "tx", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "origin", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": ",", + "highlight": "normal" + }, + { + "start": 41, + "end": 84, + "content": "\"Require that message sender is tx-origin.\"", + "highlight": "string" + }, + { + "start": 84, + "end": 85, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 8, + "end": 92, + "content": "/* require(msg.sender == tx.origin, \"Require that message sender is tx-origin.\"); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 40, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 30, + "content": "checkSignature", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 40, + "content": "signature", + "highlight": "normal" + }, + { + "start": 40, + "end": 41, + "content": ",", + "highlight": "normal" + }, + { + "start": 42, + "end": 53, + "content": "beneficiary", + "highlight": "normal" + }, + { + "start": 53, + "end": 54, + "content": ",", + "highlight": "normal" + }, + { + "start": 55, + "end": 61, + "content": "amount", + "highlight": "normal" + }, + { + "start": 61, + "end": 62, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 62, + "end": 63, + "content": ",", + "highlight": "normal" + }, + { + "start": 64, + "end": 93, + "content": "\"Not eligible to claim AVAX!\"", + "highlight": "string" + }, + { + "start": 93, + "end": 94, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 40, + "changes": [ + { + "start": 8, + "end": 101, + "content": "/* require(checkSignature(signature, beneficiary, amount), \"Not eligible to claim AVAX!\"); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/4/FVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/4/FVR/AirdropAVAX.sol new file mode 100644 index 00000000000..7625ac85d55 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/4/FVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) public { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) external { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) external view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/4/FVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/4/FVR/diff_result_difft.json new file mode 100644 index 00000000000..f51eed20624 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/4/FVR/diff_result_difft.json @@ -0,0 +1,110 @@ +{ + "number_of_changes": 4, + "timing": 0.11318850517272949, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 38, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 40, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 65, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 63, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 68, + "end": 74, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 68, + "end": 76, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 54, + "changes": [ + { + "start": 84, + "end": 90, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 54, + "changes": [ + { + "start": 84, + "end": 92, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/4/TOR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/4/TOR/AirdropAVAX.sol new file mode 100644 index 00000000000..2c1a63cdecb --- /dev/null +++ b/contracts/mutants/AirdropAVAX/4/TOR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(tx.origin == msg.sender, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = tx.origin; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[tx.origin] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/4/TOR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/4/TOR/diff_result_difft.json new file mode 100644 index 00000000000..990e2c00026 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/4/TOR/diff_result_difft.json @@ -0,0 +1,142 @@ +{ + "number_of_changes": 11, + "timing": 0.20915746688842773, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 30, + "end": 33, + "content": "msg", + "highlight": "normal" + }, + { + "start": 34, + "end": 40, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 30, + "end": 32, + "content": "tx", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "origin", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": ".", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + }, + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 26, + "end": 28, + "content": "==", + "highlight": "keyword" + }, + { + "start": 29, + "end": 32, + "content": "msg", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "sender", + "highlight": "normal" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 44, + "changes": [ + { + "start": 19, + "end": 22, + "content": "msg", + "highlight": "normal" + }, + { + "start": 23, + "end": 29, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 44, + "changes": [ + { + "start": 19, + "end": 21, + "content": "tx", + "highlight": "normal" + }, + { + "start": 22, + "end": 28, + "content": "origin", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/5/EHC/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/5/EHC/AirdropAVAX.sol new file mode 100644 index 00000000000..08df5651e57 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/5/EHC/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + /* require(success, "AVAX transfer failed."); */ + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + /* require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); */ + // Make sure user didn't claim + /* require(!wasClaimed[beneficiary], "Already claimed AVAX!"); */ + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/5/EHC/diff_result_difft.json b/contracts/mutants/AirdropAVAX/5/EHC/diff_result_difft.json new file mode 100644 index 00000000000..d5ddedcef4a --- /dev/null +++ b/contracts/mutants/AirdropAVAX/5/EHC/diff_result_difft.json @@ -0,0 +1,402 @@ +{ + "number_of_changes": 50, + "timing": 0.11033892631530762, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 22, + "content": "_admin", + "highlight": "normal" + }, + { + "start": 23, + "end": 25, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 26, + "end": 33, + "content": "address", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 34, + "end": 35, + "content": "0", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 37, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 8, + "end": 44, + "content": "/* require(_admin != address(0)); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 23, + "content": "success", + "highlight": "normal" + }, + { + "start": 23, + "end": 24, + "content": ",", + "highlight": "normal" + }, + { + "start": 25, + "end": 48, + "content": "\"AVAX transfer failed.\"", + "highlight": "string" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* require(success, \"AVAX transfer failed.\"); */", + "highlight": "comment" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 40, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 30, + "content": "checkSignature", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 40, + "content": "signature", + "highlight": "normal" + }, + { + "start": 40, + "end": 41, + "content": ",", + "highlight": "normal" + }, + { + "start": 42, + "end": 53, + "content": "beneficiary", + "highlight": "normal" + }, + { + "start": 53, + "end": 54, + "content": ",", + "highlight": "normal" + }, + { + "start": 55, + "end": 61, + "content": "amount", + "highlight": "normal" + }, + { + "start": 61, + "end": 62, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 62, + "end": 63, + "content": ",", + "highlight": "normal" + }, + { + "start": 64, + "end": 93, + "content": "\"Not eligible to claim AVAX!\"", + "highlight": "string" + }, + { + "start": 93, + "end": 94, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 40, + "changes": [ + { + "start": 8, + "end": 101, + "content": "/* require(checkSignature(signature, beneficiary, amount), \"Not eligible to claim AVAX!\"); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 17, + "content": "!", + "highlight": "keyword" + }, + { + "start": 17, + "end": 27, + "content": "wasClaimed", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "[", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 39, + "content": "beneficiary", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "]", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 41, + "content": ",", + "highlight": "normal" + }, + { + "start": 42, + "end": 65, + "content": "\"Already claimed AVAX!\"", + "highlight": "string" + }, + { + "start": 65, + "end": 66, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 73, + "content": "/* require(!wasClaimed[beneficiary], \"Already claimed AVAX!\"); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 8, + "end": 15, + "content": "require", + "highlight": "normal" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 16, + "end": 19, + "content": "msg", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": ".", + "highlight": "normal" + }, + { + "start": 20, + "end": 26, + "content": "sender", + "highlight": "normal" + }, + { + "start": 27, + "end": 29, + "content": "==", + "highlight": "keyword" + }, + { + "start": 30, + "end": 32, + "content": "tx", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "origin", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": ",", + "highlight": "normal" + }, + { + "start": 41, + "end": 84, + "content": "\"Require that message sender is tx-origin.\"", + "highlight": "string" + }, + { + "start": 84, + "end": 85, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 8, + "end": 92, + "content": "/* require(msg.sender == tx.origin, \"Require that message sender is tx-origin.\"); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/5/FVR/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/5/FVR/AirdropAVAX.sol new file mode 100644 index 00000000000..43e62b851ce --- /dev/null +++ b/contracts/mutants/AirdropAVAX/5/FVR/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) public { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) external { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) external view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) external view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropAVAX/5/FVR/diff_result_difft.json b/contracts/mutants/AirdropAVAX/5/FVR/diff_result_difft.json new file mode 100644 index 00000000000..69880d2f648 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/5/FVR/diff_result_difft.json @@ -0,0 +1,136 @@ +{ + "number_of_changes": 5, + "timing": 0.11995792388916016, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 38, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 32, + "end": 40, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 65, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 57, + "end": 63, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 68, + "end": 74, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 68, + "end": 76, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 54, + "changes": [ + { + "start": 84, + "end": 90, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 54, + "changes": [ + { + "start": 84, + "end": 92, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 61, + "changes": [ + { + "start": 89, + "end": 95, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 61, + "changes": [ + { + "start": 89, + "end": 97, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/AirdropAVAX/original/AirdropAVAX.sol b/contracts/mutants/AirdropAVAX/original/AirdropAVAX.sol new file mode 100644 index 00000000000..b4fe0509221 --- /dev/null +++ b/contracts/mutants/AirdropAVAX/original/AirdropAVAX.sol @@ -0,0 +1,67 @@ +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropAVAX { + + using ECDSA for bytes32; + using SafeMath for *; + + IAdmin public admin; + uint256 public totalTokensWithdrawn; + + mapping (address => bool) public wasClaimed; + + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address _admin) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + } + + // Function to withdraw tokens. + function withdrawTokens(bytes memory signature, uint256 amount) public { + // Allow only direct - not contract calls. + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Get beneficiary address + address beneficiary = msg.sender; + // Verify signature + require(checkSignature(signature, beneficiary, amount), "Not eligible to claim AVAX!"); + // Make sure user didn't claim + require(!wasClaimed[beneficiary], "Already claimed AVAX!"); + // Mark that user already claimed. + wasClaimed[msg.sender] = true; + // Transfer AVAX to user + safeTransferAVAX(beneficiary, amount); + // Increase amount of AVAX withdrawn + totalTokensWithdrawn = totalTokensWithdrawn.add(amount); + // Trigger event that AVAX is sent. + emit SentAVAX(beneficiary, amount); + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, uint256 amount) public view returns (address) { + bytes32 hash = keccak256(abi.encodePacked(beneficiary, amount, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, uint256 amount) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, amount)); + } + + receive() external payable {} +} diff --git a/contracts/mutants/AirdropCampaign/1/BLR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/BLR/AirdropCampaign.sol new file mode 100644 index 00000000000..4d431276796 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/BLR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = false; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..5056f79fa24 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/CCD/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/CCD/AirdropCampaign.sol new file mode 100644 index 00000000000..3815de974ef --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/CCD/AirdropCampaign.sol @@ -0,0 +1,47 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/CSC/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/CSC/AirdropCampaign.sol new file mode 100644 index 00000000000..6e62c0b856b --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/CSC/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (true) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/EHC/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/EHC/AirdropCampaign.sol new file mode 100644 index 00000000000..a9d0282fe5b --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/EHC/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + /* require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); */ + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/ILR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/ILR/AirdropCampaign.sol new file mode 100644 index 00000000000..5cebba89945 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/ILR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 1; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/MOI/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/MOI/AirdropCampaign.sol new file mode 100644 index 00000000000..9979994a0e3 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/MOI/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() ownerOnly { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/TOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/TOR/AirdropCampaign.sol new file mode 100644 index 00000000000..c0a7ea655f2 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/TOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[tx.origin] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/UORD/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/UORD/AirdropCampaign.sol new file mode 100644 index 00000000000..39189293069 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/UORD/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits--; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/1/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/1/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..0744c63fc9e --- /dev/null +++ b/contracts/mutants/AirdropCampaign/1/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/10/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/10/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..8aafd343fcd --- /dev/null +++ b/contracts/mutants/AirdropCampaign/10/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 internal bronzeRewardTokens; + uint8 internal silverRewardTokens; + uint8 internal goldRewardTokens; + uint8 internal silverRewardDistance; //each x-th investor gets silver reward + uint8 internal goldRewardDistance; //each x-th investor gets gold reward + bool internal isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/2/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/2/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..a0aa5d766ef --- /dev/null +++ b/contracts/mutants/AirdropCampaign/2/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/2/CSC/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/2/CSC/AirdropCampaign.sol new file mode 100644 index 00000000000..a0c09f1affb --- /dev/null +++ b/contracts/mutants/AirdropCampaign/2/CSC/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (true) { + tokenAmount = goldRewardTokens; + } else if (true) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/2/ILR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/2/ILR/AirdropCampaign.sol new file mode 100644 index 00000000000..bdb6a7f559f --- /dev/null +++ b/contracts/mutants/AirdropCampaign/2/ILR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 1; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 1 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/2/TOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/2/TOR/AirdropCampaign.sol new file mode 100644 index 00000000000..754785ff990 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/2/TOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[tx.origin] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(tx.origin, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/2/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/2/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..b1629a008fb --- /dev/null +++ b/contracts/mutants/AirdropCampaign/2/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/3/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/3/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..a650d6a0e6c --- /dev/null +++ b/contracts/mutants/AirdropCampaign/3/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 || soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/3/ILR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/3/ILR/AirdropCampaign.sol new file mode 100644 index 00000000000..ad4c85025e0 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/3/ILR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 1; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 1 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 1) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/3/TOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/3/TOR/AirdropCampaign.sol new file mode 100644 index 00000000000..03db9a0eeb8 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/3/TOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[tx.origin] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(tx.origin, tokenAmount); + buyers[tx.origin] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/3/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/3/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..38695deffe4 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/3/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/4/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/4/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..9c5bfc507d1 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/4/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 || soldUnits <= maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/4/ILR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/4/ILR/AirdropCampaign.sol new file mode 100644 index 00000000000..d65d6d03a8a --- /dev/null +++ b/contracts/mutants/AirdropCampaign/4/ILR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 1; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 1 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 1) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 1) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/4/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/4/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..afcef6d4670 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/4/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/5/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/5/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..3ac53880c03 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/5/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 || soldUnits <= maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits + goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/5/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/5/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..76428258f39 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/5/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 internal bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/6/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/6/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..8bc964cd9eb --- /dev/null +++ b/contracts/mutants/AirdropCampaign/6/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 || soldUnits <= maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits + goldRewardDistance <= 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/6/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/6/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..43d7b222e56 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/6/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 internal bronzeRewardTokens; + uint8 internal silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/7/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/7/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..644937ff567 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/7/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 || soldUnits <= maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits + goldRewardDistance <= 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits + silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/7/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/7/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..494fbe2bbf7 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/7/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 internal bronzeRewardTokens; + uint8 internal silverRewardTokens; + uint8 internal goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/8/BOR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/8/BOR/AirdropCampaign.sol new file mode 100644 index 00000000000..d3d46808a56 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/8/BOR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive || buyers[msg.sender] <= 0 || soldUnits <= maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits + goldRewardDistance <= 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits + silverRewardDistance <= 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/8/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/8/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..f2c6284c6cf --- /dev/null +++ b/contracts/mutants/AirdropCampaign/8/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 internal bronzeRewardTokens; + uint8 internal silverRewardTokens; + uint8 internal goldRewardTokens; + uint8 internal silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/9/VVR/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/9/VVR/AirdropCampaign.sol new file mode 100644 index 00000000000..3f1431abb5a --- /dev/null +++ b/contracts/mutants/AirdropCampaign/9/VVR/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken internal token; + string internal name; + uint32 internal maxUnits; + uint32 internal soldUnits; + uint8 internal bronzeRewardTokens; + uint8 internal silverRewardTokens; + uint8 internal goldRewardTokens; + uint8 internal silverRewardDistance; //each x-th investor gets silver reward + uint8 internal goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropCampaign/original/AirdropCampaign.sol b/contracts/mutants/AirdropCampaign/original/AirdropCampaign.sol new file mode 100644 index 00000000000..fb66dfd0ab1 --- /dev/null +++ b/contracts/mutants/AirdropCampaign/original/AirdropCampaign.sol @@ -0,0 +1,69 @@ +pragma solidity ^0.4.10; + +import "../token/MintableToken.sol"; +import "../common/Owned.sol"; + +contract AirdropCampaign is Owned { + + MintableToken public token; + string public name; + uint32 public maxUnits; + uint32 public soldUnits; + uint8 public bronzeRewardTokens; + uint8 public silverRewardTokens; + uint8 public goldRewardTokens; + uint8 public silverRewardDistance; //each x-th investor gets silver reward + uint8 public goldRewardDistance; //each x-th investor gets gold reward + bool public isActive; + + /**@dev List of buyers to prevent multiple purchases */ + mapping (address => uint256) public buyers; + + //Triggers when all payments are successfully done + //event ProductBought(address buyer, uint256 quantity, string clientId); + + function AirdropCampaign( + MintableToken _token, + string _name, + uint32 _maxUnits, + uint8 _bronzeReward, + uint8 _silverReward, + uint8 _goldReward, + uint8 _silverDistance, + uint8 _goldDistance, + bool _active) { + + isActive = true; + soldUnits = 0; + token = _token; + name = _name; + maxUnits = _maxUnits; + bronzeRewardTokens = _bronzeReward; + silverRewardTokens = _silverReward; + goldRewardTokens = _goldReward; + silverRewardDistance = _silverDistance; + goldRewardDistance = _goldDistance; + isActive = _active; + } + + function buy() { + require(isActive && buyers[msg.sender] == 0 && soldUnits < maxUnits); + soldUnits++; + + uint256 tokenAmount = bronzeRewardTokens; + if (soldUnits % goldRewardDistance == 0) { + tokenAmount = goldRewardTokens; + } else if (soldUnits % silverRewardDistance == 0) { + tokenAmount = silverRewardTokens; + } + + //tokenAmount = token.getRealTokenAmount(tokenAmount); //considering decimals + + token.mint(msg.sender, tokenAmount); + buyers[msg.sender] = tokenAmount; + } + + function setActive(bool state) ownerOnly { + isActive = state; + } +} \ No newline at end of file diff --git a/contracts/mutants/AirdropSale/1/BLR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/BLR/AirdropSale.sol new file mode 100644 index 00000000000..f95d4910cb4 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/BLR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = false;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/BOR/AirdropSale.sol new file mode 100644 index 00000000000..3abebfcfadf --- /dev/null +++ b/contracts/mutants/AirdropSale/1/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/CCD/AirdropSale.sol b/contracts/mutants/AirdropSale/1/CCD/AirdropSale.sol new file mode 100644 index 00000000000..8a65c759ad6 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/CCD/AirdropSale.sol @@ -0,0 +1,111 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/1/CSC/AirdropSale.sol new file mode 100644 index 00000000000..093b06b6727 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/CSC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/DLR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/DLR/AirdropSale.sol new file mode 100644 index 00000000000..86df240c969 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/DLR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] storage _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/EED/AirdropSale.sol b/contracts/mutants/AirdropSale/1/EED/AirdropSale.sol new file mode 100644 index 00000000000..2ef5f288a4c --- /dev/null +++ b/contracts/mutants/AirdropSale/1/EED/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + /* emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); */ + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/1/EHC/AirdropSale.sol new file mode 100644 index 00000000000..717462e1533 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/ETR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/ETR/AirdropSale.sol new file mode 100644 index 00000000000..66f114e0575 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/ETR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).send(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/FVR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/FVR/AirdropSale.sol new file mode 100644 index 00000000000..45ee2b8db08 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/FVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/ILR/AirdropSale.sol new file mode 100644 index 00000000000..70d5001a0fe --- /dev/null +++ b/contracts/mutants/AirdropSale/1/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/MCR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/MCR/AirdropSale.sol new file mode 100644 index 00000000000..6c43b748711 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/MCR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = sha256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/RSD/AirdropSale.sol b/contracts/mutants/AirdropSale/1/RSD/AirdropSale.sol new file mode 100644 index 00000000000..cfcb798dd9e --- /dev/null +++ b/contracts/mutants/AirdropSale/1/RSD/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + /* return messageHash.recover(signature); */ + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/SFR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/SFR/AirdropSale.sol new file mode 100644 index 00000000000..b57fb41b80f --- /dev/null +++ b/contracts/mutants/AirdropSale/1/SFR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.sub(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/TOR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/TOR/AirdropSale.sol new file mode 100644 index 00000000000..5636d6106c6 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/TOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(tx.origin == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/UORD/AirdropSale.sol b/contracts/mutants/AirdropSale/1/UORD/AirdropSale.sol new file mode 100644 index 00000000000..1ca51a21a6e --- /dev/null +++ b/contracts/mutants/AirdropSale/1/UORD/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i--) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/1/VVR/AirdropSale.sol b/contracts/mutants/AirdropSale/1/VVR/AirdropSale.sol new file mode 100644 index 00000000000..0e995e34367 --- /dev/null +++ b/contracts/mutants/AirdropSale/1/VVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin internal immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/10/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/10/ILR/AirdropSale.sol new file mode 100644 index 00000000000..ad1a1de2907 --- /dev/null +++ b/contracts/mutants/AirdropSale/10/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(0) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 1; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[1]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 0; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 1) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(1)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/BLR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/BLR/AirdropSale.sol new file mode 100644 index 00000000000..f9791d65fad --- /dev/null +++ b/contracts/mutants/AirdropSale/2/BLR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = false;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = false; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/BOR/AirdropSale.sol new file mode 100644 index 00000000000..ca6d23c5c9b --- /dev/null +++ b/contracts/mutants/AirdropSale/2/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/2/CSC/AirdropSale.sol new file mode 100644 index 00000000000..9ce5564cf0a --- /dev/null +++ b/contracts/mutants/AirdropSale/2/CSC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(true) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/DLR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/DLR/AirdropSale.sol new file mode 100644 index 00000000000..503df752e2b --- /dev/null +++ b/contracts/mutants/AirdropSale/2/DLR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] storage _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes storage signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/EED/AirdropSale.sol b/contracts/mutants/AirdropSale/2/EED/AirdropSale.sol new file mode 100644 index 00000000000..a1d725ecb8e --- /dev/null +++ b/contracts/mutants/AirdropSale/2/EED/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + /* emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); */ + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + /* emit SentAVAX(to, value); */ + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/2/EHC/AirdropSale.sol new file mode 100644 index 00000000000..973e1b74755 --- /dev/null +++ b/contracts/mutants/AirdropSale/2/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/ETR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/ETR/AirdropSale.sol new file mode 100644 index 00000000000..d7369081b8c --- /dev/null +++ b/contracts/mutants/AirdropSale/2/ETR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).send(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.delegatecall(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/FVR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/FVR/AirdropSale.sol new file mode 100644 index 00000000000..8a624546a03 --- /dev/null +++ b/contracts/mutants/AirdropSale/2/FVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) public { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/ILR/AirdropSale.sol new file mode 100644 index 00000000000..d4f825dec64 --- /dev/null +++ b/contracts/mutants/AirdropSale/2/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/MCR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/MCR/AirdropSale.sol new file mode 100644 index 00000000000..d40aeea808e --- /dev/null +++ b/contracts/mutants/AirdropSale/2/MCR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = sha256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = sha256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/RSD/AirdropSale.sol b/contracts/mutants/AirdropSale/2/RSD/AirdropSale.sol new file mode 100644 index 00000000000..0eee8d5904e --- /dev/null +++ b/contracts/mutants/AirdropSale/2/RSD/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + /* return messageHash.recover(signature); */ + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + /* return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); */ + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/SFR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/SFR/AirdropSale.sol new file mode 100644 index 00000000000..c5f0ab23ff7 --- /dev/null +++ b/contracts/mutants/AirdropSale/2/SFR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.sub(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.add(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/TOR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/TOR/AirdropSale.sol new file mode 100644 index 00000000000..a6fbc49d955 --- /dev/null +++ b/contracts/mutants/AirdropSale/2/TOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(tx.origin == msg.sender, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/UORD/AirdropSale.sol b/contracts/mutants/AirdropSale/2/UORD/AirdropSale.sol new file mode 100644 index 00000000000..0231d65c2e8 --- /dev/null +++ b/contracts/mutants/AirdropSale/2/UORD/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i--) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require( wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/2/VVR/AirdropSale.sol b/contracts/mutants/AirdropSale/2/VVR/AirdropSale.sol new file mode 100644 index 00000000000..73793740c3d --- /dev/null +++ b/contracts/mutants/AirdropSale/2/VVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin internal immutable admin; + address[] internal airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/BLR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/BLR/AirdropSale.sol new file mode 100644 index 00000000000..15cf24f8f9f --- /dev/null +++ b/contracts/mutants/AirdropSale/3/BLR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = false;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = false; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = false; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/BOR/AirdropSale.sol new file mode 100644 index 00000000000..3c3b24a48bf --- /dev/null +++ b/contracts/mutants/AirdropSale/3/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/3/CSC/AirdropSale.sol new file mode 100644 index 00000000000..1870cf90ead --- /dev/null +++ b/contracts/mutants/AirdropSale/3/CSC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(true) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(true) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/DLR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/DLR/AirdropSale.sol new file mode 100644 index 00000000000..f504f0e25ea --- /dev/null +++ b/contracts/mutants/AirdropSale/3/DLR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] storage _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes storage signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes storage signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/3/EHC/AirdropSale.sol new file mode 100644 index 00000000000..f33b5ebdad1 --- /dev/null +++ b/contracts/mutants/AirdropSale/3/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/FVR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/FVR/AirdropSale.sol new file mode 100644 index 00000000000..e7cb86b56b6 --- /dev/null +++ b/contracts/mutants/AirdropSale/3/FVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) public { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) external view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/ILR/AirdropSale.sol new file mode 100644 index 00000000000..8025a3b6126 --- /dev/null +++ b/contracts/mutants/AirdropSale/3/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/SFR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/SFR/AirdropSale.sol new file mode 100644 index 00000000000..33a2f94867c --- /dev/null +++ b/contracts/mutants/AirdropSale/3/SFR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.sub(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.add(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].sub(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/TOR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/TOR/AirdropSale.sol new file mode 100644 index 00000000000..b25bf1a7fae --- /dev/null +++ b/contracts/mutants/AirdropSale/3/TOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(tx.origin == msg.sender, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = tx.origin; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/UORD/AirdropSale.sol b/contracts/mutants/AirdropSale/3/UORD/AirdropSale.sol new file mode 100644 index 00000000000..f115526728a --- /dev/null +++ b/contracts/mutants/AirdropSale/3/UORD/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i--) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require( wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i--) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/3/VVR/AirdropSale.sol b/contracts/mutants/AirdropSale/3/VVR/AirdropSale.sol new file mode 100644 index 00000000000..a7624b8e2f7 --- /dev/null +++ b/contracts/mutants/AirdropSale/3/VVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin internal immutable admin; + address[] internal airdropERC20s; + bool internal includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/4/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/4/BOR/AirdropSale.sol new file mode 100644 index 00000000000..c4e7cfadd5c --- /dev/null +++ b/contracts/mutants/AirdropSale/4/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] > address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/4/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/4/CSC/AirdropSale.sol new file mode 100644 index 00000000000..3595332b43e --- /dev/null +++ b/contracts/mutants/AirdropSale/4/CSC/AirdropSale.sol @@ -0,0 +1,125 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(true) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(true) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/4/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/4/EHC/AirdropSale.sol new file mode 100644 index 00000000000..8583b70cc6a --- /dev/null +++ b/contracts/mutants/AirdropSale/4/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + /* require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); */ + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/4/FVR/AirdropSale.sol b/contracts/mutants/AirdropSale/4/FVR/AirdropSale.sol new file mode 100644 index 00000000000..d56a524353f --- /dev/null +++ b/contracts/mutants/AirdropSale/4/FVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) public { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) external view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) external view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/4/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/4/ILR/AirdropSale.sol new file mode 100644 index 00000000000..a0499a7b289 --- /dev/null +++ b/contracts/mutants/AirdropSale/4/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/4/VVR/AirdropSale.sol b/contracts/mutants/AirdropSale/4/VVR/AirdropSale.sol new file mode 100644 index 00000000000..c8575d98ec1 --- /dev/null +++ b/contracts/mutants/AirdropSale/4/VVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin internal immutable admin; + address[] internal airdropERC20s; + bool internal includesAVAX; + bool internal includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/5/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/5/BOR/AirdropSale.sol new file mode 100644 index 00000000000..26ec5c0e35f --- /dev/null +++ b/contracts/mutants/AirdropSale/5/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] > address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender <= tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/5/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/5/CSC/AirdropSale.sol new file mode 100644 index 00000000000..bf5a5a9f35b --- /dev/null +++ b/contracts/mutants/AirdropSale/5/CSC/AirdropSale.sol @@ -0,0 +1,125 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(true) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(true) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(true) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/5/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/5/EHC/AirdropSale.sol new file mode 100644 index 00000000000..17663629948 --- /dev/null +++ b/contracts/mutants/AirdropSale/5/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + /* require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); */ + } else { + /* require(airdropERC20s.length == amounts.length, "Array size mismatch."); */ + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/5/FVR/AirdropSale.sol b/contracts/mutants/AirdropSale/5/FVR/AirdropSale.sol new file mode 100644 index 00000000000..ffb49a30b55 --- /dev/null +++ b/contracts/mutants/AirdropSale/5/FVR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) internal { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) public { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) external view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) external view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) public { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/5/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/5/ILR/AirdropSale.sol new file mode 100644 index 00000000000..d26704a2b27 --- /dev/null +++ b/contracts/mutants/AirdropSale/5/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(0) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/6/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/6/BOR/AirdropSale.sol new file mode 100644 index 00000000000..1f67d71e9aa --- /dev/null +++ b/contracts/mutants/AirdropSale/6/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] > address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender <= tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) <= amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/6/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/6/CSC/AirdropSale.sol new file mode 100644 index 00000000000..9f790c6f848 --- /dev/null +++ b/contracts/mutants/AirdropSale/6/CSC/AirdropSale.sol @@ -0,0 +1,125 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(true) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(true) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(true) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(true) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/6/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/6/EHC/AirdropSale.sol new file mode 100644 index 00000000000..26a6e8234d7 --- /dev/null +++ b/contracts/mutants/AirdropSale/6/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + /* require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); */ + } else { + /* require(airdropERC20s.length == amounts.length, "Array size mismatch."); */ + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + /* require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); */ + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/6/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/6/ILR/AirdropSale.sol new file mode 100644 index 00000000000..84baae30a40 --- /dev/null +++ b/contracts/mutants/AirdropSale/6/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(0) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 1; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/7/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/7/BOR/AirdropSale.sol new file mode 100644 index 00000000000..bcb500eec23 --- /dev/null +++ b/contracts/mutants/AirdropSale/7/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] > address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender <= tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) <= amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length <= amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/7/CSC/AirdropSale.sol b/contracts/mutants/AirdropSale/7/CSC/AirdropSale.sol new file mode 100644 index 00000000000..abce484c3bb --- /dev/null +++ b/contracts/mutants/AirdropSale/7/CSC/AirdropSale.sol @@ -0,0 +1,125 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(true) {includesAVAX = true;} + + // Add airdrop tokens to array + if(true) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(true) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(true) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(true) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(true) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/7/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/7/EHC/AirdropSale.sol new file mode 100644 index 00000000000..a5f017b4944 --- /dev/null +++ b/contracts/mutants/AirdropSale/7/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + /* require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); */ + } else { + /* require(airdropERC20s.length == amounts.length, "Array size mismatch."); */ + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + /* require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); */ + // Require that user didn't claim already + /* require(!wasClaimed[beneficiary], "Already claimed!"); */ + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/7/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/7/ILR/AirdropSale.sol new file mode 100644 index 00000000000..e74f0cbad5b --- /dev/null +++ b/contracts/mutants/AirdropSale/7/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(0) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 1; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[1]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/8/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/8/BOR/AirdropSale.sol new file mode 100644 index 00000000000..459f7828581 --- /dev/null +++ b/contracts/mutants/AirdropSale/8/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] > address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender <= tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) <= amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length <= amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i <= amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/8/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/8/EHC/AirdropSale.sol new file mode 100644 index 00000000000..5fba35a42e1 --- /dev/null +++ b/contracts/mutants/AirdropSale/8/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + /* require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); */ + } else { + /* require(airdropERC20s.length == amounts.length, "Array size mismatch."); */ + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + /* require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); */ + // Require that user didn't claim already + /* require(!wasClaimed[beneficiary], "Already claimed!"); */ + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + /* require(status, "Token transfer status is false."); */ + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/8/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/8/ILR/AirdropSale.sol new file mode 100644 index 00000000000..cb65244eb23 --- /dev/null +++ b/contracts/mutants/AirdropSale/8/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(0) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 1; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[1]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 0; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/9/BOR/AirdropSale.sol b/contracts/mutants/AirdropSale/9/BOR/AirdropSale.sol new file mode 100644 index 00000000000..cae5aadd88d --- /dev/null +++ b/contracts/mutants/AirdropSale/9/BOR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin > address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length > 0) { + includesERC20s = true; + for(uint i = 0; i <= _airdropERC20s.length; i++) { + require(_airdropERC20s[i] > address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender <= tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) <= amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length <= amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i <= amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] >= 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/9/EHC/AirdropSale.sol b/contracts/mutants/AirdropSale/9/EHC/AirdropSale.sol new file mode 100644 index 00000000000..ed2edd26419 --- /dev/null +++ b/contracts/mutants/AirdropSale/9/EHC/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + /* require(_admin != address(0)); */ + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + /* require(_airdropERC20s[i] != address(0)); */ + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + /* require(msg.sender == tx.origin, "Require that message sender is tx-origin."); */ + // Require that array sizes are matching + if(includesAVAX) { + /* require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); */ + } else { + /* require(airdropERC20s.length == amounts.length, "Array size mismatch."); */ + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + /* require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); */ + // Require that user didn't claim already + /* require(!wasClaimed[beneficiary], "Already claimed!"); */ + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + /* require(status, "Token transfer status is false."); */ + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + /* require(success, "AVAX transfer failed."); */ + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/9/ILR/AirdropSale.sol b/contracts/mutants/AirdropSale/9/ILR/AirdropSale.sol new file mode 100644 index 00000000000..8f97160122d --- /dev/null +++ b/contracts/mutants/AirdropSale/9/ILR/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(1)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 1) { + includesERC20s = true; + for(uint i = 1; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(1)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(0) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 1; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[1]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 0; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 1) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +} diff --git a/contracts/mutants/AirdropSale/original/AirdropSale.sol b/contracts/mutants/AirdropSale/original/AirdropSale.sol new file mode 100644 index 00000000000..375b03b612f --- /dev/null +++ b/contracts/mutants/AirdropSale/original/AirdropSale.sol @@ -0,0 +1,127 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "../interfaces/IAdmin.sol"; +import "../math/SafeMath.sol"; + +contract AirdropSale { + + using ECDSA for bytes32; + using SafeMath for uint256; + + // Globals + IAdmin public immutable admin; + address[] public airdropERC20s; + bool public includesAVAX; + bool public includesERC20s; + mapping (address => uint256) public tokenToTotalWithdrawn; + mapping (address => bool) public wasClaimed; + + // Events + event SentERC20(address beneficiary, address token, uint256 amount); + event SentAVAX(address beneficiary, uint256 amount); + + // Constructor, initial setup + constructor(address[] memory _airdropERC20s, address _admin, bool _includesAVAX) public { + require(_admin != address(0)); + admin = IAdmin(_admin); + + // Mark if contract airdrops AVAX + if(_includesAVAX) {includesAVAX = true;} + + // Add airdrop tokens to array + if(_airdropERC20s.length != 0) { + includesERC20s = true; + for(uint i = 0; i < _airdropERC20s.length; i++) { + require(_airdropERC20s[i] != address(0)); + airdropERC20s.push(_airdropERC20s[i]); + } + } + // else: leave includesERC20 on false/default + } + + /// @notice Function to withdraw tokens + function withdrawTokens( + bytes calldata signature, + uint256[] calldata amounts + ) external { + // Allow only direct call + require(msg.sender == tx.origin, "Require that message sender is tx-origin."); + // Require that array sizes are matching + if(includesAVAX) { + require(airdropERC20s.length.add(1) == amounts.length, "Array size mismatch."); + } else { + require(airdropERC20s.length == amounts.length, "Array size mismatch."); + } + + // Get beneficiary address + address beneficiary = msg.sender; + + // Hash amounts array to get a compact and unique value for signing + bytes32 hashedAmounts = keccak256(abi.encodePacked(amounts)); + // Validate signature + require(checkSignature(signature, beneficiary, hashedAmounts), "Not eligible to claim tokens!"); + // Require that user didn't claim already + require(!wasClaimed[beneficiary], "Already claimed!"); + // Mark that user claimed + wasClaimed[beneficiary] = true; + + // Amounts array's ERC20 distribution starting index + uint startIndex = 0; + + // Only if airdrop includes AVAX + if(includesAVAX) { + // Perform AVAX safeTransferAVAX + safeTransferAVAX(beneficiary, amounts[0]); + // Switch startIndex to 1 if airdropping AVAX + startIndex = 1; + } + + // Only if airdrop includes ERC20s + if(includesERC20s) { + // Go through all of the airdrop tokens + for(uint i = startIndex; i < amounts.length; i++) { + // Allows to skip token transfers for user's on order + if(amounts[i] > 0) { + // Compute airdropERC20s proper index + uint j = i.sub(startIndex); + // Perform transfer + bool status = IERC20(airdropERC20s[j]).transfer(beneficiary, amounts[i]); + // Require that transfer was successful + require(status, "Token transfer status is false."); + // Increase token's withdrawn amount + tokenToTotalWithdrawn[airdropERC20s[j]] = tokenToTotalWithdrawn[airdropERC20s[j]].add(amounts[i]); + // Trigger event that token is sent + emit SentERC20(beneficiary,airdropERC20s[j], amounts[i]); + } + } + } + } + + // Get who signed the message based on the params + function getSigner(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (address) { + bytes32 hash = keccak256(abi.encode(beneficiary, hashedAmounts, address(this))); + bytes32 messageHash = hash.toEthSignedMessageHash(); + return messageHash.recover(signature); + } + + // Check that signature is valid, and is signed by Admin wallets + function checkSignature(bytes memory signature, address beneficiary, bytes32 hashedAmounts) public view returns (bool) { + return admin.isAdmin(getSigner(signature, beneficiary, hashedAmounts)); + } + + // Safe transfer AVAX to users + function safeTransferAVAX(address to, uint256 value) internal { + // Safely transfer AVAX to address + (bool success, ) = to.call{value: value}(new bytes(0)); + // Require that transfer was successful. + require(success, "AVAX transfer failed."); + // Trigger relevant event + emit SentAVAX(to, value); + } + + // Enable receiving AVAX + receive() external payable {} +}