-
Notifications
You must be signed in to change notification settings - Fork 970
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2576 from crytic/dev-chainlink-feed-detector
Add Chainlink feed registry detector
- Loading branch information
Showing
6 changed files
with
148 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
from typing import List | ||
|
||
from slither.detectors.abstract_detector import ( | ||
AbstractDetector, | ||
DetectorClassification, | ||
DETECTOR_INFO, | ||
) | ||
from slither.utils.output import Output | ||
|
||
|
||
class ChainlinkFeedRegistry(AbstractDetector): | ||
|
||
ARGUMENT = "chainlink-feed-registry" | ||
HELP = "Detect when chainlink feed registry is used" | ||
IMPACT = DetectorClassification.LOW | ||
CONFIDENCE = DetectorClassification.HIGH | ||
|
||
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry" | ||
|
||
WIKI_TITLE = "Chainlink Feed Registry usage" | ||
WIKI_DESCRIPTION = "Detect when Chainlink Feed Registry is used. At the moment is only available on Ethereum Mainnet." | ||
|
||
# region wiki_exploit_scenario | ||
WIKI_EXPLOIT_SCENARIO = """ | ||
```solidity | ||
import "chainlink/contracts/src/v0.8/interfaces/FeedRegistryInteface.sol" | ||
contract A { | ||
FeedRegistryInterface public immutable registry; | ||
constructor(address _registry) { | ||
registry = _registry; | ||
} | ||
function getPrice(address base, address quote) public return(uint256) { | ||
(, int256 price,,,) = registry.latestRoundData(base, quote); | ||
// Do price validation | ||
return uint256(price); | ||
} | ||
} | ||
``` | ||
If the contract is deployed on a different chain than Ethereum Mainnet the `getPrice` function will revert. | ||
""" | ||
# endregion wiki_exploit_scenario | ||
|
||
WIKI_RECOMMENDATION = "Do not use Chainlink Feed Registry outside of Ethereum Mainnet." | ||
|
||
def _detect(self) -> List[Output]: | ||
# https://github.com/smartcontractkit/chainlink/blob/8ca41fc8f722accfccccb4b1778db2df8fef5437/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol | ||
registry_functions = [ | ||
"decimals", | ||
"description", | ||
"versiom", | ||
"latestRoundData", | ||
"getRoundData", | ||
"latestAnswer", | ||
"latestTimestamp", | ||
"latestRound", | ||
"getAnswer", | ||
"getTimestamp", | ||
"getFeed", | ||
"getPhaseFeed", | ||
"isFeedEnabled", | ||
"getPhase", | ||
"getRoundFeed", | ||
"getPhaseRange", | ||
"getPreviousRoundId", | ||
"getNextRoundId", | ||
"proposeFeed", | ||
"confirmFeed", | ||
"getProposedFeed", | ||
"proposedGetRoundData", | ||
"proposedLatestRoundData", | ||
"getCurrentPhaseId", | ||
] | ||
results = [] | ||
|
||
for contract in self.compilation_unit.contracts_derived: | ||
nodes = [] | ||
for target, ir in contract.all_high_level_calls: | ||
if ( | ||
target.name == "FeedRegistryInterface" | ||
and ir.function_name in registry_functions | ||
): | ||
nodes.append(ir.node) | ||
# Sort so output is deterministic | ||
nodes.sort(key=lambda x: (x.node_id, x.function.full_name)) | ||
|
||
if len(nodes) > 0: | ||
info: DETECTOR_INFO = [ | ||
"The Chainlink Feed Registry is used in the ", | ||
contract.name, | ||
" contract. It's only available on Ethereum Mainnet, consider to not use it if the contract needs to be deployed on other chains.\n", | ||
] | ||
|
||
for node in nodes: | ||
info.extend(["\t - ", node, "\n"]) | ||
|
||
res = self.generate_result(info) | ||
results.append(res) | ||
|
||
return results |
3 changes: 3 additions & 0 deletions
3
...shots/detectors__detector_ChainlinkFeedRegistry_0_8_20_chainlink_feed_registry_sol__0.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
The Chainlink Feed Registry is used in the A contract. It's only available on Ethereum Mainnet, consider to not use it if the contract needs to be deployed on other chains. | ||
- (None,price,None,None,None) = registry.latestRoundData(base,quote) (tests/e2e/detectors/test_data/chainlink-feed-registry/0.8.20/chainlink_feed_registry.sol#25) | ||
|
37 changes: 37 additions & 0 deletions
37
tests/e2e/detectors/test_data/chainlink-feed-registry/0.8.20/chainlink_feed_registry.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
interface FeedRegistryInterface { | ||
function latestRoundData( | ||
address base, | ||
address quote | ||
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); | ||
} | ||
|
||
interface MyInterface { | ||
function latestRoundData( | ||
address base, | ||
address quote | ||
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); | ||
} | ||
|
||
contract A { | ||
FeedRegistryInterface public immutable registry; | ||
MyInterface public immutable my_interface; | ||
|
||
constructor(FeedRegistryInterface _registry, MyInterface _my_interface) { | ||
registry = _registry; | ||
my_interface = _my_interface; | ||
} | ||
|
||
function getPriceBad(address base, address quote) public returns (uint256) { | ||
(, int256 price,,,) = registry.latestRoundData(base, quote); | ||
// Do price validation | ||
return uint256(price); | ||
} | ||
|
||
function getPriceGood(address base, address quote) public returns (uint256) { | ||
(, int256 price,,,) = my_interface.latestRoundData(base, quote); | ||
// Do price validation | ||
return uint256(price); | ||
} | ||
|
||
|
||
} |
Binary file added
BIN
+5.72 KB
...detectors/test_data/chainlink-feed-registry/0.8.20/chainlink_feed_registry.sol-0.8.20.zip
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters