oracle_soroban_kit/
lib.rs

1/*
2    Copyright (c) 2023-2024 Frederic Kyung-jin Rezeau (오경진 吳景振)
3
4    This file is part of soroban-kit.
5
6    Licensed under the MIT License, this software is provided "AS IS",
7    no liability assumed. For details, see the LICENSE file in the
8    root directory.
9
10    Author: Fred Kyung-jin Rezeau <fred@litemint.com>
11*/
12
13// This example implements a simple Oracle Broker to handle synchronous and asynchronous
14// topic-based requests for a fee.
15
16#![no_std]
17
18use soroban_kit::{oracle, oracle_broker};
19use soroban_sdk::{
20    contract, contractimpl, contracttype, token, Address, Bytes, Env, TryIntoVal, Vec,
21};
22
23#[contracttype]
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct Message {
26    pub data: Bytes,
27    pub timestamp: u64,
28}
29
30#[contracttype]
31#[derive(Clone, Debug, Eq, PartialEq)]
32pub enum Database {
33    Topic(Bytes),
34}
35
36#[contract]
37// In this example, we use `Bytes` (native type) for the topic and a custom type
38// `Message` for the data. All built-in and user defined types are supported.
39#[oracle_broker(Bytes, Message)]
40pub struct OracleContract;
41
42// Implement the Oracle events trait.
43impl oracle::Events<Bytes, Message> for OracleContract {
44    // This event is fired for each data requests.
45    fn on_subscribe(env: &Env, topic: &Bytes, envelope: &oracle::Envelope) -> Option<Message> {
46        // Retrieve the envelopes for this topic.
47        let mut envelopes = if env.storage().instance().has::<Bytes>(topic) {
48            env.storage()
49                .instance()
50                .get::<Bytes, Vec<oracle::Envelope>>(topic)
51                .unwrap()
52        } else {
53            Vec::new(env)
54        };
55
56        // Here, you typically handle authentication,
57        // apply filters for routers, subscribers, topics,
58        // other checks as needed.
59
60        // Example: topic-based filter.
61        // assert_eq!(*topic, bytes![env, [1, 2, 3]]);
62
63        // Example: Enforce max envelopes per topics.
64        // assert!(envelopes.len() < 5);
65
66        // In this example, we demonstrate how to charge a fee
67        // for all subscriber requests.
68        envelope.subscriber.require_auth();
69        token::Client::new(
70            &env,
71            &Address::from_string(
72                &"CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"
73                    .try_into_val(env)
74                    .unwrap(),
75            ),
76        )
77        .transfer(
78            &envelope.subscriber,
79            &env.current_contract_address(),
80            &10000000,
81        );
82
83        // Return the data synchronously if available.
84        if env
85            .storage()
86            .instance()
87            .has(&Database::Topic(topic.clone()))
88        {
89            env.storage()
90                .instance()
91                .get::<_, Message>(&Database::Topic(topic.clone()))
92        } else {
93            // Otherwise, add the envelope for asynchronous publishing.
94            envelopes.push_back(envelope.clone());
95            env.storage()
96                .instance()
97                .set::<Bytes, Vec<oracle::Envelope>>(topic, &envelopes);
98            None
99        }
100    }
101
102    // This event is fired for each publishing requests.
103    fn on_publish(
104        env: &Env,
105        topic: &Bytes,
106        data: &Message,
107        _publisher: &Address,
108    ) -> Vec<oracle::Envelope> {
109        // Here, you typically handle authentication for publishers
110        // other checks as needed.
111
112        // Store the data for synchronous requests.
113        env.storage()
114            .instance()
115            .set::<_, Message>(&Database::Topic(topic.clone()), data);
116
117        // In this example, we simply return all envelopes @topic
118        let envelopes = env
119            .storage()
120            .instance()
121            .get::<Bytes, Vec<oracle::Envelope>>(topic)
122            .unwrap();
123        env.storage().instance().remove::<Bytes>(topic);
124        envelopes
125    }
126}
127
128// That's it! Ready to deploy your Oracle broker contract!