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}