multiversx_sc_modules/bonding_curve/utils/
owner_endpoints.rs

1multiversx_sc::imports!();
2multiversx_sc::derive_imports!();
3
4use multiversx_sc::contract_base::ManagedSerializer;
5
6use crate::bonding_curve::{
7    curves::curve_function::CurveFunction,
8    utils::{
9        events, storage,
10        structs::{BondingCurve, TokenOwnershipData},
11    },
12};
13
14use super::structs::CurveArguments;
15
16#[multiversx_sc::module]
17pub trait OwnerEndpointsModule: storage::StorageModule + events::EventsModule {
18    #[endpoint(setLocalRoles)]
19    fn set_local_roles(
20        &self,
21        address: ManagedAddress,
22        token_identifier: TokenIdentifier,
23        roles: MultiValueEncoded<EsdtLocalRole>,
24    ) {
25        self.send()
26            .esdt_system_sc_proxy()
27            .set_special_roles(&address, &token_identifier, roles.into_iter())
28            .async_call_and_exit()
29    }
30
31    #[endpoint(unsetLocalRoles)]
32    fn unset_local_roles(
33        &self,
34        address: ManagedAddress,
35        token_identifier: TokenIdentifier,
36        roles: MultiValueEncoded<EsdtLocalRole>,
37    ) {
38        self.send()
39            .esdt_system_sc_proxy()
40            .unset_special_roles(&address, &token_identifier, roles.into_iter())
41            .async_call_and_exit()
42    }
43
44    fn set_bonding_curve<T>(
45        &self,
46        identifier: TokenIdentifier,
47        function: T,
48        sell_availability: bool,
49    ) where
50        T: CurveFunction<Self::Api>
51            + TopEncode
52            + TopDecode
53            + NestedEncode
54            + NestedDecode
55            + TypeAbi
56            + PartialEq
57            + Default,
58    {
59        require!(
60            !self.token_details(&identifier).is_empty(),
61            "Token is not issued yet!"
62        );
63
64        let caller = self.blockchain().get_caller();
65
66        let details = self.token_details(&identifier).get();
67        require!(
68            details.owner == caller,
69            "The price function can only be set by the seller."
70        );
71        self.bonding_curve(&identifier).update(|buffer| {
72            let serializer = ManagedSerializer::new();
73
74            let mut bonding_curve: BondingCurve<Self::Api, T> =
75                serializer.top_decode_from_managed_buffer(buffer);
76            bonding_curve.curve = function;
77            bonding_curve.sell_availability = sell_availability;
78            *buffer = serializer.top_encode_to_managed_buffer(&bonding_curve);
79        });
80    }
81
82    fn deposit<T>(&self, payment_token: OptionalValue<TokenIdentifier>)
83    where
84        T: CurveFunction<Self::Api>
85            + TopEncode
86            + TopDecode
87            + NestedEncode
88            + NestedDecode
89            + TypeAbi
90            + PartialEq
91            + Default,
92    {
93        let esdt_payment = self.call_value().single_esdt();
94        let identifier = &esdt_payment.token_identifier;
95        let nonce = esdt_payment.token_nonce;
96        let amount = &esdt_payment.amount;
97        let caller = self.blockchain().get_caller();
98        let mut set_payment = EgldOrEsdtTokenIdentifier::egld();
99
100        if self.bonding_curve(identifier).is_empty() {
101            match payment_token {
102                OptionalValue::Some(token) => set_payment = EgldOrEsdtTokenIdentifier::esdt(token),
103                OptionalValue::None => {
104                    sc_panic!("Expected provided accepted_payment for the token");
105                },
106            };
107        }
108        if self.token_details(identifier).is_empty() {
109            let nonces = ManagedVec::from_single_item(nonce);
110            self.token_details(identifier).set(&TokenOwnershipData {
111                token_nonces: nonces,
112                owner: caller.clone(),
113            });
114        } else {
115            let mut details = self.token_details(identifier).get();
116            require!(
117                details.owner == caller,
118                "The token was already deposited by another address"
119            );
120            if !details.token_nonces.contains(&nonce) {
121                details.token_nonces.push(nonce);
122                self.token_details(identifier).set(&details);
123            }
124        }
125
126        self.set_curve_storage::<T>(identifier, amount.clone(), set_payment);
127        self.owned_tokens(&caller).insert(identifier.clone());
128        self.nonce_amount(identifier, nonce)
129            .update(|current_amount| *current_amount += amount);
130    }
131
132    fn claim<T>(&self)
133    where
134        T: CurveFunction<Self::Api>
135            + TopEncode
136            + TopDecode
137            + NestedEncode
138            + NestedDecode
139            + TypeAbi
140            + PartialEq
141            + Default,
142    {
143        let caller = self.blockchain().get_caller();
144        require!(
145            !self.owned_tokens(&caller).is_empty(),
146            "You have nothing to claim"
147        );
148
149        let mut tokens_to_claim = ManagedVec::<Self::Api, EsdtTokenPayment<Self::Api>>::new();
150        let mut egld_to_claim = BigUint::zero();
151        let serializer = ManagedSerializer::new();
152        for token in self.owned_tokens(&caller).iter() {
153            let nonces = self.token_details(&token).get().token_nonces;
154            for nonce in &nonces {
155                tokens_to_claim.push(EsdtTokenPayment::new(
156                    token.clone(),
157                    nonce,
158                    self.nonce_amount(&token, nonce).get(),
159                ));
160
161                self.nonce_amount(&token, nonce).clear();
162            }
163
164            let bonding_curve: BondingCurve<Self::Api, T> =
165                serializer.top_decode_from_managed_buffer(&self.bonding_curve(&token).get());
166
167            if let Some(esdt_token_identifier) =
168                bonding_curve.payment.token_identifier.into_esdt_option()
169            {
170                tokens_to_claim.push(EsdtTokenPayment::new(
171                    esdt_token_identifier,
172                    bonding_curve.payment.token_nonce,
173                    bonding_curve.payment.amount,
174                ));
175            } else {
176                egld_to_claim += bonding_curve.payment.amount;
177            }
178
179            self.token_details(&token).clear();
180            self.bonding_curve(&token).clear();
181        }
182        self.owned_tokens(&caller).clear();
183        self.tx().to(&caller).multi_esdt(tokens_to_claim).transfer();
184        if egld_to_claim > BigUint::zero() {
185            self.tx().to(&caller).egld(&egld_to_claim).transfer();
186        }
187    }
188
189    fn set_curve_storage<T>(
190        &self,
191        identifier: &TokenIdentifier,
192        amount: BigUint,
193        payment_token_identifier: EgldOrEsdtTokenIdentifier,
194    ) where
195        T: CurveFunction<Self::Api>
196            + TopEncode
197            + TopDecode
198            + NestedEncode
199            + NestedDecode
200            + TypeAbi
201            + PartialEq
202            + Default,
203    {
204        let mut curve: T = T::default();
205        let mut arguments;
206        let payment;
207        let sell_availability: bool;
208        let serializer = ManagedSerializer::new();
209
210        if self.bonding_curve(identifier).is_empty() {
211            arguments = CurveArguments {
212                available_supply: amount.clone(),
213                balance: amount,
214            };
215            payment = EgldOrEsdtTokenPayment::new(payment_token_identifier, 0, BigUint::zero());
216            sell_availability = false;
217        } else {
218            let bonding_curve: BondingCurve<Self::Api, T> =
219                serializer.top_decode_from_managed_buffer(&self.bonding_curve(identifier).get());
220
221            payment = bonding_curve.payment;
222            curve = bonding_curve.curve;
223            arguments = bonding_curve.arguments;
224            arguments.balance += &amount;
225            arguments.available_supply += amount;
226            sell_availability = bonding_curve.sell_availability;
227        }
228        let encoded_curve = serializer.top_encode_to_managed_buffer(&BondingCurve {
229            curve,
230            arguments,
231            sell_availability,
232            payment,
233        });
234        self.bonding_curve(identifier).set(encoded_curve);
235    }
236}