@@ -45,25 +45,48 @@ var (
4545type LLOAggregatorConfig struct {
4646 // workaround for the fact that mapstructure doesn't support uint32 keys
4747 //streams map[uint32]feedConfig `mapstructure:"-"`
48- StreamsStr map [string ]feedConfig `mapstructure:"streams"`
48+ Streams map [string ]FeedConfig `mapstructure:"streams"`
4949 // allowedPartialStaleness is an optional optimization that tries to maximize batching.
5050 // Once any deviation or heartbeat threshold hits, we will include all other feeds that are
5151 // within the allowedPartialStaleness range of their own heartbeat.
5252 // For example, setting 0.2 will include all feeds that are within 20% of their heartbeat.
5353 //allowedPartialStaleness float64 `mapstructure:"-"`
5454 // workaround for the fact that mapstructure doesn't support float64 keys
55- AllowedPartialStalenessStr string `mapstructure:"allowedPartialStaleness"`
55+ AllowedPartialStaleness string `mapstructure:"allowedPartialStaleness"`
56+ }
57+
58+ // ToMap converts the LLOAggregatorConfig to a values.Map, which is suitable for the
59+ // [NewAggegator] function in the OCR3 Aggregator interface.
60+ func (c LLOAggregatorConfig ) ToMap () (* values.Map , error ) {
61+ v , err := values .WrapMap (c )
62+ if err != nil {
63+ // this should never happen since we are wrapping a struct
64+ return & values.Map {}, fmt .Errorf ("failed to wrap LLOAggregatorConfig: %w" , err )
65+ }
66+ return v , nil
67+ }
68+
69+ func NewLLOConfig (m values.Map ) (LLOAggregatorConfig , error ) {
70+ // Create a default LLOAggregatorConfig
71+ config := LLOAggregatorConfig {
72+ Streams : make (map [string ]FeedConfig ),
73+ }
74+ if err := m .UnwrapTo (& config ); err != nil {
75+ return LLOAggregatorConfig {}, fmt .Errorf ("failed to unwrap values.Map to LLOAggregatorConfig: %w" , err )
76+ }
77+
78+ return config , nil
5679}
5780
5881func (c LLOAggregatorConfig ) convertToInternal () (parsedLLOAggregatorConfig , error ) {
5982 parsedConfig := parsedLLOAggregatorConfig {
60- streams : make (map [uint32 ]feedConfig ),
83+ streams : make (map [uint32 ]FeedConfig ),
6184 }
6285 cfgErr := func (err error ) error {
6386 cfgErr := fmt .Errorf ("llo aggregator config: %w" , ErrInvalidConfig )
6487 return errors .Join (cfgErr , err )
6588 }
66- for s , cfg := range c .StreamsStr {
89+ for s , cfg := range c .Streams {
6790 id , err := strconv .ParseUint (s , 10 , 32 )
6891 if err != nil {
6992 // this should never happen since we are using a mapstructure-compatible config
@@ -77,25 +100,25 @@ func (c LLOAggregatorConfig) convertToInternal() (parsedLLOAggregatorConfig, err
77100 if cfg .RemappedIDHex == "" {
78101 return parsedConfig , cfgErr (fmt .Errorf ("remappedID is required for stream %d" , streamID ))
79102 }
80- if cfg .DeviationString != "" {
81- dec , err := decimal .NewFromString (cfg .DeviationString )
103+ if cfg .Deviation != "" {
104+ dec , err := decimal .NewFromString (cfg .Deviation )
82105 if err != nil {
83106 return parsedConfig , cfgErr (fmt .Errorf ("cannot parse deviation config for feed %d: %w" , streamID , err ))
84107 }
85- cfg .Deviation = dec
108+ cfg .parsedDeviation = dec
86109 parsedConfig .streams [streamID ] = cfg
87110 }
88111 trimmed := strings .TrimPrefix (cfg .RemappedIDHex , "0x" )
89112 rawRemappedID , err := hex .DecodeString (trimmed )
90113 if err != nil {
91114 return parsedConfig , cfgErr (fmt .Errorf ("cannot parse remappedId config for feed %d: %w" , streamID , err ))
92115 }
93- cfg .RemappedID = rawRemappedID
116+ cfg .remappedID = rawRemappedID
94117 parsedConfig .streams [streamID ] = cfg
95118 }
96119 // convert allowedPartialStaleness from string to float64
97- if c .AllowedPartialStalenessStr != "" {
98- allowedPartialStaleness , err := decimal .NewFromString (c .AllowedPartialStalenessStr )
120+ if c .AllowedPartialStaleness != "" {
121+ allowedPartialStaleness , err := decimal .NewFromString (c .AllowedPartialStaleness )
99122 if err != nil {
100123 return parsedConfig , cfgErr (fmt .Errorf ("cannot parse allowedPartialStaleness: %w" , err ))
101124 }
@@ -108,7 +131,7 @@ func (c LLOAggregatorConfig) convertToInternal() (parsedLLOAggregatorConfig, err
108131// the separation is because mapstructure only supports string keys.
109132// the are exposed in LLOAggregatorConfig for the config which is then processed into this internal representation.
110133type parsedLLOAggregatorConfig struct {
111- streams map [uint32 ]feedConfig
134+ streams map [uint32 ]FeedConfig
112135 allowedPartialStaleness float64
113136}
114137
@@ -118,6 +141,8 @@ type LLOAggregator struct {
118141 config parsedLLOAggregatorConfig
119142}
120143
144+ // NewLLOAggregator creates a new LLOAggregator instance based on the provided configuration.
145+ // The config should be a [values.Map] that has represents from the [LLOAggregatorConfig]. See [LLOAggreagatorConfig.ToMap]
121146func NewLLOAggregator (config values.Map ) (types.Aggregator , error ) {
122147 parsedConfig , err := parseLLOConfig (config )
123148 if err != nil {
@@ -180,10 +205,10 @@ func (a *LLOAggregator) Aggregate(lggr logger.Logger, previousOutcome *types.Agg
180205 "oldPrice" , oldPrice ,
181206 "newPrice" , newPrice ,
182207 "currDeviation" , priceDeviation ,
183- "deviation" , config .Deviation .InexactFloat64 (),
208+ "deviation" , config .DeviationAsDecimal () .InexactFloat64 (),
184209 )
185210 if timeDiffNs > config .HeartbeatNanos () ||
186- priceDeviation > config .Deviation .InexactFloat64 () {
211+ priceDeviation > config .DeviationAsDecimal () .InexactFloat64 () {
187212 // this stream needs an update
188213 previousStreamInfo .Timestamp = observationTimestamp .UnixNano ()
189214 var err2 error
@@ -214,7 +239,7 @@ func (a *LLOAggregator) Aggregate(lggr logger.Logger, previousOutcome *types.Agg
214239
215240 toWrap := make ([]* EVMEncodableStreamUpdate , 0 , len (mustUpdateIDs ))
216241 for _ , streamID := range mustUpdateIDs {
217- remappedID := a .config .streams [streamID ].RemappedID
242+ remappedID := a .config .streams [streamID ].RemappedID ()
218243 newPrice := prices [streamID ]
219244 w := & EVMEncodableStreamUpdate {
220245 StreamID : streamID ,
@@ -413,7 +438,7 @@ func lloStreamPrices(lggr logger.Logger, wantStreamIDs []uint32, lloEvents map[o
413438// parseLLOConfig parses the user-facing, type-less, LLO aggregator in the internal typed config.
414439func parseLLOConfig (config values.Map ) (parsedLLOAggregatorConfig , error ) {
415440 converter := LLOAggregatorConfig {
416- StreamsStr : make (map [string ]feedConfig ),
441+ Streams : make (map [string ]FeedConfig ),
417442 }
418443 if err := config .UnwrapTo (& converter ); err != nil {
419444 return parsedLLOAggregatorConfig {}, err
0 commit comments