1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use alloy_primitives::{Address, B256};
/// Known aggregator storage layouts.
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AggregatorLayout {
/// Chainlink OCR2 `AccessControlledOCR2Aggregator 1.0.0` compatible layout.
ChainlinkOcr2V1,
/// Chainlink OCR1 `AccessControlledOffchainAggregator 2.0.0` compatible layout.
ChainlinkOcr1V2,
/// Chainlink OCR1 `AccessControlledOffchainAggregator 3.0.0` compatible layout.
ChainlinkOcr1V3,
/// Chainlink OCR1 `AccessControlledOffchainAggregator 4.0.0` compatible layout.
ChainlinkOcr1V4,
/// The aggregator exposed a version string, but this crate has no direct
/// storage adapter for it.
Unsupported,
/// No usable layout evidence was available.
Unknown,
}
/// How an aggregator layout was detected.
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AggregatorLayoutConfidence {
/// The layout came directly from `typeAndVersion()`.
TypeAndVersion,
/// The layout came from a previously observed matching code hash.
CodeHashCache,
/// No usable evidence was available.
Unknown,
}
/// Evidence collected while identifying an aggregator implementation.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AggregatorLayoutEvidence {
/// Aggregator address that was inspected.
pub aggregator: Address,
/// Raw `typeAndVersion()` result, when available.
pub type_and_version: Option<String>,
/// Runtime code hash, when available from the provider.
pub code_hash: Option<B256>,
/// Classified layout.
pub layout: AggregatorLayout,
/// Detection confidence.
pub confidence: AggregatorLayoutConfidence,
}
impl AggregatorLayoutEvidence {
/// Build evidence from a `typeAndVersion()` read and optional code hash.
pub fn from_type_and_version(
aggregator: Address,
type_and_version: impl Into<String>,
code_hash: Option<B256>,
) -> Self {
let type_and_version = type_and_version.into();
Self {
aggregator,
layout: classify_type_and_version(&type_and_version),
type_and_version: Some(type_and_version),
code_hash,
confidence: AggregatorLayoutConfidence::TypeAndVersion,
}
}
/// Build evidence from a code-hash cache hit.
pub fn from_code_hash_cache(
aggregator: Address,
code_hash: B256,
layout: AggregatorLayout,
) -> Self {
Self {
aggregator,
type_and_version: None,
code_hash: Some(code_hash),
layout,
confidence: AggregatorLayoutConfidence::CodeHashCache,
}
}
/// Build unknown evidence for an aggregator.
pub fn unknown(aggregator: Address, code_hash: Option<B256>) -> Self {
Self {
aggregator,
type_and_version: None,
code_hash,
layout: AggregatorLayout::Unknown,
confidence: AggregatorLayoutConfidence::Unknown,
}
}
/// Return true when the evidence supports OCR2 direct storage sync.
pub fn is_chainlink_ocr2_v1(&self) -> bool {
self.layout == AggregatorLayout::ChainlinkOcr2V1
}
/// Return true when the evidence supports a Chainlink OCR1 direct-storage layout.
pub fn is_chainlink_ocr1(&self) -> bool {
matches!(
self.layout,
AggregatorLayout::ChainlinkOcr1V2
| AggregatorLayout::ChainlinkOcr1V3
| AggregatorLayout::ChainlinkOcr1V4
)
}
}
/// Classify a Chainlink-style `typeAndVersion()` string.
pub fn classify_type_and_version(type_and_version: &str) -> AggregatorLayout {
match type_and_version.trim() {
"AccessControlledOCR2Aggregator 1.0.0" | "OCR2Aggregator 1.0.0" => {
AggregatorLayout::ChainlinkOcr2V1
}
"AccessControlledOffchainAggregator 2.0.0" | "OffchainAggregator 2.0.0" => {
AggregatorLayout::ChainlinkOcr1V2
}
"AccessControlledOffchainAggregator 3.0.0" | "OffchainAggregator 3.0.0" => {
AggregatorLayout::ChainlinkOcr1V3
}
"AccessControlledOffchainAggregator 4.0.0" | "OffchainAggregator 4.0.0" => {
AggregatorLayout::ChainlinkOcr1V4
}
"" => AggregatorLayout::Unknown,
_ => AggregatorLayout::Unsupported,
}
}