drt_sc_modules/bonding_curve/utils/
user_endpoints.rs

1drt_sc::imports!();
2drt_sc::derive_imports!();
3
4use drt_sc::contract_base::ManagedSerializer;
5
6use crate::bonding_curve::{
7    curves::curve_function::CurveFunction,
8    utils::{events, storage, structs::BondingCurve},
9};
10
11#[drt_sc::module]
12pub trait UserEndpointsModule: storage::StorageModule + events::EventsModule {
13    fn sell_token<T>(&self)
14    where
15        T: CurveFunction<Self::Api>
16            + TopEncode
17            + TopDecode
18            + NestedEncode
19            + NestedDecode
20            + TypeAbi
21            + PartialEq
22            + Default,
23    {
24        let (offered_token, nonce, sell_amount) = self.call_value().single_dcdt().into_tuple();
25        let _ = self.check_owned_return_payment_token::<T>(&offered_token, &sell_amount);
26
27        let (calculated_price, payment_token) =
28            self.bonding_curve(&offered_token).update(|buffer| {
29                let serializer = ManagedSerializer::new();
30
31                let mut bonding_curve: BondingCurve<Self::Api, T> =
32                    serializer.top_decode_from_managed_buffer(buffer);
33
34                require!(
35                    bonding_curve.sell_availability,
36                    "Selling is not available on this token"
37                );
38                let price = self.compute_sell_price::<T>(&offered_token, &sell_amount);
39                bonding_curve.payment.amount -= &price;
40                bonding_curve.arguments.balance += &sell_amount;
41                let payment_token = bonding_curve.payment_token();
42                *buffer = serializer.top_encode_to_managed_buffer(&bonding_curve);
43                (price, payment_token)
44            });
45
46        let caller = self.blockchain().get_caller();
47
48        self.nonce_amount(&offered_token, nonce)
49            .update(|val| *val += sell_amount);
50
51        self.tx()
52            .to(&caller)
53            .rewa_or_single_dcdt(&payment_token, 0u64, &calculated_price)
54            .transfer();
55
56        self.token_details(&offered_token)
57            .update(|details| details.add_nonce(nonce));
58
59        self.sell_token_event(&caller, &calculated_price);
60    }
61
62    fn buy_token<T>(
63        &self,
64        requested_amount: BigUint,
65        requested_token: TokenIdentifier,
66        requested_nonce: OptionalValue<u64>,
67    ) where
68        T: CurveFunction<Self::Api>
69            + TopEncode
70            + TopDecode
71            + NestedEncode
72            + NestedDecode
73            + TypeAbi
74            + PartialEq
75            + Default,
76    {
77        let (offered_token, payment) = self.call_value().rewa_or_single_fungible_dcdt();
78        let payment_token =
79            self.check_owned_return_payment_token::<T>(&requested_token, &requested_amount);
80        self.check_given_token(&payment_token, &offered_token);
81
82        let calculated_price = self.bonding_curve(&requested_token).update(|buffer| {
83            let serializer = ManagedSerializer::new();
84
85            let mut bonding_curve: BondingCurve<Self::Api, T> =
86                serializer.top_decode_from_managed_buffer(buffer);
87
88            let price = self.compute_buy_price::<T>(&requested_token, &requested_amount);
89            require!(
90                price <= payment,
91                "The payment provided is not enough for the transaction"
92            );
93            bonding_curve.payment.amount += &price;
94            bonding_curve.arguments.balance -= &requested_amount;
95            *buffer = serializer.top_encode_to_managed_buffer(&bonding_curve);
96
97            price
98        });
99
100        let caller = self.blockchain().get_caller();
101
102        match requested_nonce {
103            OptionalValue::Some(nonce) => {
104                self.tx()
105                    .to(&caller)
106                    .single_dcdt(&requested_token, nonce, &requested_amount)
107                    .transfer();
108                if self.nonce_amount(&requested_token, nonce).get() - requested_amount.clone() > 0 {
109                    self.nonce_amount(&requested_token, nonce)
110                        .update(|val| *val -= requested_amount.clone());
111                } else {
112                    self.nonce_amount(&requested_token, nonce).clear();
113                    self.token_details(&requested_token)
114                        .update(|details| details.remove_nonce(nonce));
115                }
116            },
117            OptionalValue::None => {
118                self.send_next_available_tokens(&caller, requested_token, requested_amount);
119            },
120        };
121
122        self.tx()
123            .to(&caller)
124            .rewa_or_single_dcdt(&offered_token, 0u64, &(&payment - &calculated_price))
125            .transfer();
126
127        self.buy_token_event(&caller, &calculated_price);
128    }
129
130    fn send_next_available_tokens(
131        &self,
132        caller: &ManagedAddress,
133        token: TokenIdentifier,
134        amount: BigUint,
135    ) {
136        let mut nonces = self.token_details(&token).get().token_nonces;
137        let mut total_amount = amount;
138        let mut tokens_to_send = ManagedVec::<Self::Api, DcdtTokenPayment<Self::Api>>::new();
139        loop {
140            require!(!nonces.is_empty(), "Insufficient balance");
141            let nonce = nonces.get(0);
142            let available_amount = self.nonce_amount(&token, nonce).get();
143
144            let amount_to_send: BigUint;
145            if available_amount <= total_amount {
146                amount_to_send = available_amount.clone();
147                total_amount -= amount_to_send.clone();
148                self.nonce_amount(&token, nonce).clear();
149                nonces.remove(0);
150            } else {
151                self.nonce_amount(&token, nonce)
152                    .update(|val| *val -= total_amount.clone());
153                amount_to_send = total_amount.clone();
154                total_amount = BigUint::zero();
155            }
156            tokens_to_send.push(DcdtTokenPayment::new(token.clone(), nonce, amount_to_send));
157            if total_amount == BigUint::zero() {
158                break;
159            }
160        }
161
162        self.tx().to(caller).multi_dcdt(tokens_to_send).transfer();
163
164        self.token_details(&token)
165            .update(|token_ownership| token_ownership.token_nonces = nonces);
166    }
167
168    fn get_buy_price<T>(&self, amount: BigUint, identifier: TokenIdentifier) -> BigUint
169    where
170        T: CurveFunction<Self::Api>
171            + TopEncode
172            + TopDecode
173            + NestedEncode
174            + NestedDecode
175            + TypeAbi
176            + PartialEq
177            + Default,
178    {
179        self.check_token_exists(&identifier);
180        self.compute_buy_price::<T>(&identifier, &amount)
181    }
182
183    fn get_sell_price<T>(&self, amount: BigUint, identifier: TokenIdentifier) -> BigUint
184    where
185        T: CurveFunction<Self::Api>
186            + TopEncode
187            + TopDecode
188            + NestedEncode
189            + NestedDecode
190            + TypeAbi
191            + PartialEq
192            + Default,
193    {
194        self.check_token_exists(&identifier);
195        self.compute_sell_price::<T>(&identifier, &amount)
196    }
197
198    fn check_token_exists(&self, issued_token: &TokenIdentifier) {
199        require!(
200            !self.bonding_curve(issued_token).is_empty(),
201            "Token is not issued yet!"
202        );
203    }
204
205    #[view(getTokenAvailability)]
206    fn get_token_availability(
207        &self,
208        identifier: TokenIdentifier,
209    ) -> MultiValueEncoded<MultiValue2<u64, BigUint>> {
210        let token_nonces = self.token_details(&identifier).get().token_nonces;
211        let mut availability = MultiValueEncoded::new();
212
213        for current_check_nonce in &token_nonces {
214            availability.push(MultiValue2((
215                current_check_nonce,
216                self.nonce_amount(&identifier, current_check_nonce).get(),
217            )));
218        }
219        availability
220    }
221
222    fn check_owned_return_payment_token<T>(
223        &self,
224        issued_token: &TokenIdentifier,
225        amount: &BigUint,
226    ) -> RewaOrDcdtTokenIdentifier
227    where
228        T: CurveFunction<Self::Api>
229            + TopEncode
230            + TopDecode
231            + NestedEncode
232            + NestedDecode
233            + TypeAbi
234            + PartialEq
235            + Default,
236    {
237        self.check_token_exists(issued_token);
238
239        let serializer = ManagedSerializer::new();
240        let bonding_curve: BondingCurve<Self::Api, T> =
241            serializer.top_decode_from_managed_buffer(&self.bonding_curve(issued_token).get());
242
243        require!(
244            bonding_curve.curve != T::default(),
245            "The token price was not set yet!"
246        );
247        require!(amount > &BigUint::zero(), "Must pay more than 0 tokens!");
248        bonding_curve.payment_token()
249    }
250
251    fn check_given_token(
252        &self,
253        accepted_token: &RewaOrDcdtTokenIdentifier,
254        given_token: &RewaOrDcdtTokenIdentifier,
255    ) {
256        require!(
257            given_token == accepted_token,
258            "Only {} tokens accepted",
259            accepted_token
260        );
261    }
262
263    fn compute_buy_price<T>(&self, identifier: &TokenIdentifier, amount: &BigUint) -> BigUint
264    where
265        T: CurveFunction<Self::Api>
266            + TopEncode
267            + TopDecode
268            + NestedEncode
269            + NestedDecode
270            + TypeAbi
271            + PartialEq
272            + Default,
273    {
274        let serializer = ManagedSerializer::new();
275        let bonding_curve: BondingCurve<Self::Api, T> =
276            serializer.top_decode_from_managed_buffer(&self.bonding_curve(identifier).get());
277
278        let arguments = &bonding_curve.arguments;
279        let function_selector = &bonding_curve.curve;
280
281        let token_start = &arguments.first_token_available();
282        function_selector.calculate_price(token_start, amount, arguments)
283    }
284
285    fn compute_sell_price<T>(&self, identifier: &TokenIdentifier, amount: &BigUint) -> BigUint
286    where
287        T: CurveFunction<Self::Api>
288            + TopEncode
289            + TopDecode
290            + NestedEncode
291            + NestedDecode
292            + TypeAbi
293            + PartialEq
294            + Default,
295    {
296        let serializer = ManagedSerializer::new();
297        let bonding_curve: BondingCurve<Self::Api, T> =
298            serializer.top_decode_from_managed_buffer(&self.bonding_curve(identifier).get());
299
300        let arguments = &bonding_curve.arguments;
301        let function_selector = &bonding_curve.curve;
302
303        let token_start = arguments.first_token_available() - amount;
304        function_selector.calculate_price(&token_start, amount, arguments)
305    }
306}