multiPairSwap modified

mail@pastecode.io avatar
unknown
rust
2 years ago
5.3 kB
6
Indexable
Never
#![no_std]

elrond_wasm::imports!();
elrond_wasm::derive_imports!();

type SwapOperationType<M> =
    MultiValue4<ManagedAddress<M>, ManagedBuffer<M>, TokenIdentifier<M>, BigUint<M>>;

pub const SWAP_TOKENS_FIXED_INPUT_FUNC_NAME: &[u8] = b"swapTokensFixedInput";
pub const SWAP_TOKENS_FIXED_OUTPUT_FUNC_NAME: &[u8] = b"swapTokensFixedOutput";

mod pair {

    elrond_wasm::imports!();

    #[elrond_wasm::proxy]
    pub trait PairProxy {
        #[payable("*")]
        #[endpoint(swapTokensFixedInput)]
        fn swap_tokens_fixed_input(
            &self,
            token_out: TokenIdentifier,
            amount_out_min: BigUint,
        );

        #[payable("*")]
        #[endpoint(swapTokensFixedOutput)]
        fn swap_tokens_fixed_output(
            &self,
            token_out: TokenIdentifier,
            amount_out: BigUint,
        );
    }
}

#[elrond_wasm::module]
pub trait MultiPairSwap {

    #[init]
    fn init(&self) {
    }

    #[payable("*")]
    #[endpoint(multiPairSwap)]
    fn multi_pair_swap(&self, swap_operations: MultiValueEncoded<SwapOperationType<Self::Api>>) {
        let (token_id, nonce, amount) = self.call_value().single_esdt().into_tuple();

        let swap_fixed_input_endpoint = ManagedBuffer::from(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME);
        let swap_fixed_output_endpoint = ManagedBuffer::from(SWAP_TOKENS_FIXED_OUTPUT_FUNC_NAME);

        let caller = self.blockchain().get_caller();
        let mut payments = ManagedVec::new();
        let mut last_payment = OldEsdtTokenPayment::new(token_id, nonce, amount);

        for entry in swap_operations.into_iter() {
            let (pair_address, function, token_wanted, amount_wanted) = entry.into_tuple();

            if function == swap_fixed_input_endpoint {
                last_payment = self.actual_swap_fixed_input(
                    pair_address,
                    last_payment.token_identifier,
                    last_payment.amount,
                    token_wanted,
                    amount_wanted,
                );
            } else if function == swap_fixed_output_endpoint {
                let (payment, residuum) = self.actual_swap_fixed_output(
                    pair_address,
                    last_payment.token_identifier,
                    last_payment.amount,
                    token_wanted,
                    amount_wanted,
                );

                last_payment = payment;
                payments.push(residuum);
            } else {
                sc_panic!("Invalid function to call");
            }
        }

        payments.push(last_payment);
        self.send().direct_multi(&caller, &payments);
    }

    fn actual_swap_fixed_input(
        &self,
        pair_address: ManagedAddress,
        token_in: TokenIdentifier,
        amount_in: BigUint,
        token_out: TokenIdentifier,
        amount_out_min: BigUint,
    ) -> OldEsdtTokenPayment<Self::Api> {
        self.pair_contract_proxy(pair_address)
            .swap_tokens_fixed_input(token_out, amount_out_min)
            .add_esdt_token_transfer(token_in, 0, amount_in)
            .execute_on_dest_context()
    }

    fn actual_swap_fixed_output(
        &self,
        pair_address: ManagedAddress,
        token_in: TokenIdentifier,
        amount_in_max: BigUint,
        token_out: TokenIdentifier,
        amount_out: BigUint,
    ) -> (OldEsdtTokenPayment<Self::Api>, OldEsdtTokenPayment<Self::Api>) {
        let call_result: MultiValue2<OldEsdtTokenPayment<Self::Api>, OldEsdtTokenPayment<Self::Api>> =
            self.pair_contract_proxy(pair_address)
                .swap_tokens_fixed_output(token_out, amount_out)
                .add_esdt_token_transfer(token_in, 0, amount_in_max)
                .execute_on_dest_context();

        call_result.into_tuple()
    }

    #[proxy]
    fn pair_contract_proxy(&self, to: ManagedAddress) -> pair::Proxy<Self::Api>;
}


#[derive(TopDecode, TopEncode, NestedDecode, NestedEncode, TypeAbi, Clone, PartialEq, Debug)]
pub struct OldEsdtTokenPayment<M: ManagedTypeApi> {
    pub token_type: EsdtTokenType,
    pub token_identifier: TokenIdentifier<M>,
    pub token_nonce: u64,
    pub amount: BigUint<M>,
}

impl<M: ManagedTypeApi> OldEsdtTokenPayment<M> {
    pub fn no_payment(api: M) -> Self {
        OldEsdtTokenPayment {
            token_type: EsdtTokenType::Invalid,
            token_identifier: TokenIdentifier::egld(),
            token_nonce: 0,
            amount: BigUint::zero(),
        }
    }

    pub fn new(token_identifier: TokenIdentifier<M>, token_nonce: u64, amount: BigUint<M>) -> Self {
        let token_type = if amount != 0 && token_identifier.is_valid_esdt_identifier() {
            if token_nonce == 0 {
                EsdtTokenType::Fungible
            } else if amount == 1u64 {
                EsdtTokenType::NonFungible
            } else {
                EsdtTokenType::SemiFungible
            }
        } else {
            EsdtTokenType::Invalid
        };

        OldEsdtTokenPayment {
            token_type,
            token_identifier,
            token_nonce,
            amount,
        }
    }
}