af_oracle/event_ext/
apply.rs

1use af_sui_types::Address;
2use sui_framework_sdk::object::{ID, UID};
3
4use crate::events;
5use crate::oracle::PriceFeed;
6
7/// Intended for defining how to update off-chain data with oracle event information.
8///
9/// This should work under the following assumptions.
10///
11/// # Assumptions
12/// 1. The database is in sync with the on-chain protocol state at least up until the beginning of
13///    the event's transaction.
14pub trait Apply<T> {
15    /// Use the contents of `self` to (possibly) mutate data in `target`.
16    fn apply(self, target: &mut T);
17}
18
19/// General interface to help apply [`PriceFeedStorage`](crate::oracle::PriceFeedStorage)-related
20/// events to a database.
21pub trait PriceFeedStorage {
22    fn insert_price_feed(&mut self, source_wrapper_id: ID, feed: PriceFeed);
23
24    fn get_price_feed_mut(&mut self, source_wrapper_id: &ID) -> Option<&mut PriceFeed>;
25
26    fn remove_price_feed(&mut self, source_wrapper_id: &ID) -> Option<PriceFeed>;
27}
28
29impl<T: PriceFeedStorage> Apply<T> for events::CreatedPriceFeed {
30    fn apply(self, target: &mut T) {
31        let Self {
32            source_wrapper_id,
33            price,
34            timestamp,
35            time_tolerance,
36            ..
37        } = self;
38        let feed = PriceFeed {
39            // The event doesn't have information about the object id of the feed. Thus, we
40            // initialize it as zero to make it very clear to applications using this that the
41            // object id here is not a real one. This shouldn't be a problem since all interactions
42            // with price feeds in AfOracle are done through the `PriceFeedStorage`.
43            id: UID {
44                id: ID {
45                    bytes: Address::ZERO,
46                },
47            },
48            price,
49            timestamp,
50            time_tolerance,
51        };
52        target.insert_price_feed(source_wrapper_id, feed);
53    }
54}
55
56impl<T: PriceFeedStorage> Apply<T> for events::UpdatedPriceFeed {
57    fn apply(self, target: &mut T) {
58        let Self {
59            source_wrapper_id,
60            new_price,
61            new_timestamp,
62            ..
63        } = self;
64        // Under Assumption 1 of [`Apply`], if a price feed is not in the database at this point,
65        // it's because we're applying and old event relative to the current state and the price
66        // feed was removed later.
67        if let Some(feed) = target.get_price_feed_mut(&source_wrapper_id) {
68            feed.price = new_price;
69            feed.timestamp = new_timestamp;
70        }
71    }
72}
73
74impl<T: PriceFeedStorage> Apply<T> for events::RemovedPriceFeed {
75    fn apply(self, target: &mut T) {
76        let Self {
77            source_wrapper_id, ..
78        } = self;
79        target.remove_price_feed(&source_wrapper_id);
80    }
81}
82
83impl<T: PriceFeedStorage> Apply<T> for events::UpdatedPriceFeedTimeTolerance {
84    fn apply(self, target: &mut T) {
85        let Self {
86            source_wrapper_id,
87            new_time_tolerance,
88            ..
89        } = self;
90        // Under Assumption 1 of [`Apply`], if a price feed is not in the database at this point,
91        // it's because we're applying and old event relative to the current state and the price
92        // feed was removed later.
93        if let Some(feed) = target.get_price_feed_mut(&source_wrapper_id) {
94            feed.time_tolerance = new_time_tolerance;
95        }
96    }
97}