elrond-wasm-modules 0.29.1

Elrond WebAssembly standard smart contract modules
elrond_wasm::imports!();
elrond_wasm::derive_imports!();

use crate::bonding_curve::{
    function_selector::FunctionSelector,
    utils::{
        events, storage,
        structs::{BondingCurve, TokenOwnershipData},
    },
};

use super::structs::CurveArguments;

#[elrond_wasm::module]
pub trait OwnerEndpointsModule: storage::StorageModule + events::EventsModule {
    #[endpoint(setLocalRoles)]
    fn set_local_roles(
        &self,
        address: ManagedAddress,
        token_identifier: TokenIdentifier,
        #[var_args] roles: MultiValueEncoded<EsdtLocalRole>,
    ) {
        self.send()
            .esdt_system_sc_proxy()
            .set_special_roles(&address, &token_identifier, roles.into_iter())
            .async_call()
            .with_callback(OwnerEndpointsModule::callbacks(self).change_roles_callback())
            .call_and_exit()
    }

    #[endpoint(unsetLocalRoles)]
    fn unset_local_roles(
        &self,
        address: ManagedAddress,
        token_identifier: TokenIdentifier,
        #[var_args] roles: MultiValueEncoded<EsdtLocalRole>,
    ) {
        self.send()
            .esdt_system_sc_proxy()
            .unset_special_roles(&address, &token_identifier, roles.into_iter())
            .async_call()
            .with_callback(OwnerEndpointsModule::callbacks(self).change_roles_callback())
            .call_and_exit()
    }

    #[callback]
    fn change_roles_callback(
        &self,
        #[call_result] result: ManagedAsyncCallResult<()>,
    ) -> SCResult<(), ManagedSCError> {
        match result {
            ManagedAsyncCallResult::Ok(()) => Ok(()),
            ManagedAsyncCallResult::Err(message) => Err(message.err_msg.into()),
        }
    }

    #[endpoint(setBondingCurve)]
    fn set_bonding_curve(
        &self,
        identifier: TokenIdentifier,
        function: FunctionSelector<Self::Api>,
        sell_availability: bool,
    ) -> SCResult<()> {
        require!(
            !self.token_details(&identifier).is_empty(),
            "Token is not issued yet!"
        );

        let caller = self.blockchain().get_caller();

        let details = self.token_details(&identifier).get();
        require!(
            details.owner == caller,
            "The price function can only be set by the seller."
        );
        self.bonding_curve(&identifier).update(|bonding_curve| {
            bonding_curve.curve = function;
            bonding_curve.sell_availability = sell_availability
        });
        Ok(())
    }

    #[endpoint(deposit)]
    #[payable("*")]
    fn deposit(
        &self,
        #[payment] amount: BigUint,
        #[payment_token] identifier: TokenIdentifier,
        #[payment_nonce] nonce: u64,
        #[var_args] payment_token: OptionalValue<TokenIdentifier>,
    ) -> SCResult<()> {
        let caller = self.blockchain().get_caller();
        let mut set_payment = TokenIdentifier::egld();
        if self.bonding_curve(&identifier).is_empty() {
            set_payment = payment_token
                .into_option()
                .ok_or("Expected provided accepted_payment for the token")?;
        }
        if self.token_details(&identifier).is_empty() {
            self.token_details(&identifier).set(&TokenOwnershipData {
                token_nonces: [nonce].to_vec(),
                owner: caller.clone(),
            });
        } else {
            let mut details = self.token_details(&identifier).get();
            require!(
                details.owner == caller,
                "The token was already deposited by another address"
            );
            if !details.token_nonces.contains(&nonce) {
                details.token_nonces.push(nonce);
                self.token_details(&identifier).set(&details);
            }
        }

        self.set_curve_storage(&identifier, amount.clone(), set_payment);
        self.owned_tokens(&caller).insert(identifier.clone());
        self.nonce_amount(&identifier, nonce)
            .update(|current_amount| *current_amount += amount);
        Ok(())
    }

    #[endpoint(claim)]
    fn claim(&self) -> SCResult<()> {
        let caller = self.blockchain().get_caller();
        require!(
            !self.owned_tokens(&caller).is_empty(),
            "You have nothing to claim"
        );
        for token in self.owned_tokens(&caller).iter() {
            let nonces = self.token_details(&token).get().token_nonces;
            for nonce in nonces {
                self.send().direct(
                    &caller,
                    &token,
                    nonce,
                    &self.nonce_amount(&token, nonce).get(),
                    b"claim",
                );
                self.nonce_amount(&token, nonce).clear();
            }
            self.token_details(&token).clear();
            self.bonding_curve(&token).clear();
        }
        self.owned_tokens(&caller).clear();

        Ok(())
    }

    fn set_curve_storage(
        &self,
        identifier: &TokenIdentifier,
        amount: BigUint,
        payment: TokenIdentifier,
    ) {
        let mut curve = FunctionSelector::None;
        let mut arguments;
        let payment_token;
        let payment_amount: BigUint;
        let sell_availability: bool;

        if self.bonding_curve(identifier).is_empty() {
            arguments = CurveArguments {
                available_supply: amount.clone(),
                balance: amount,
            };
            payment_token = payment;
            payment_amount = BigUint::zero();
            sell_availability = false;
        } else {
            let bonding_curve = self.bonding_curve(identifier).get();
            payment_token = bonding_curve.payment_token;
            payment_amount = bonding_curve.payment_amount;
            curve = bonding_curve.curve;
            arguments = bonding_curve.arguments;
            arguments.balance += &amount;
            arguments.available_supply += amount;
            sell_availability = bonding_curve.sell_availability;
        }
        self.bonding_curve(identifier).set(&BondingCurve {
            curve,
            arguments,
            sell_availability,
            payment_token,
            payment_amount,
        });
    }
}