How to implement USDT to EGLD token exchange in Rust on MultiversX blockchain?

130 Views Asked by At

I am trying to fetch price of USDT in EGLD. I am using this: https://github.com/multiversx/mx-exchange-sc/blob/main/dex/pair/src/lib.rs#L604 endpoint to fetch the price. But not sure that it is right process to do it. One community member suggested me to do this.

My code is:

#![no_std]

multiversx_sc::imports!();

pub mod callee_proxy {
    multiversx_sc::imports!();
    #[multiversx_sc::proxy]
    pub trait CalleeContract {
        #[view(getAmountOut)]
        fn get_amount_out_view(&self, token_in: TokenIdentifier, amount_in: BigUint) -> BigUint;
    }
}

#[multiversx_sc::contract]
pub trait MinterContract {
    #[init]
    fn init(&self, address: ManagedAddress, price: BigUint, token_id: TokenIdentifier, usdt_token_id: TokenIdentifier)  {
         self.set_address().set(&address);
         self.set_esdt_price().set(&price);
         self.set_token_id().set(&token_id);
         self.set_usdt_token_id().set(&usdt_token_id);
    }

    #[payable("*")]
    #[endpoint]
    fn buy_token(&self, amount: BigUint) {
        require!(amount >= 1000, "Withdrawal of token amount of less than 1000 is not allowed");
        require!(amount <= 10000, "Withdrawal of token amount of more than 10000 is not allowed");
        let _price : BigUint = amount.clone() * self.set_esdt_price().get();
       let _output_amount_as_egld: BigUint = self.contract_proxy(self.set_address().get()).get_amount_out_view(self.set_token_id().get(), _price).execute_on_dest_context();

       require!(self.call_value().egld_value().clone_value() >= _output_amount_as_egld, "Not enough ELGD paid!");
       self.send().direct_esdt(&self.blockchain().get_caller(), &self.set_token_id().get(), 0, &amount);
      
        
    }

    #[endpoint]
    fn get_usdt_to_egld(&self, amount: BigUint) -> BigUint{
        let output_amount: BigUint = self.contract_proxy(self.set_address().get()).get_amount_out_view(self.set_usdt_token_id().get(), amount).execute_on_dest_context() ;
        output_amount
    }

    #[proxy]
    fn contract_proxy(&self, sc_address: ManagedAddress) -> callee_proxy::Proxy<Self::Api>;

    #[storage_mapper("Key_tokenId")]
    fn set_token_id(&self) -> SingleValueMapper<TokenIdentifier>;

    #[storage_mapper("Key_tokenId")]
    fn set_usdt_token_id(&self) -> SingleValueMapper<TokenIdentifier>;


    #[storage_mapper("key_address")]
    fn set_address(&self) -> SingleValueMapper<ManagedAddress>;

    #[storage_mapper("key_price")]
    fn set_esdt_price(&self) -> SingleValueMapper<BigUint>;

    
    
}

As you can see I created proxy like this, and declared that target endpoint. I am using this address: erd1qqqqqqqqqqqqqpgqeel2kumf0r8ffyhth7pqdujjat9nx0862jpsg2pqaq as exchange address from here: https://explorer.multiversx.com/accounts/erd1qqqqqqqqqqqqqpgqeel2kumf0r8ffyhth7pqdujjat9nx0862jpsg2pqaq/tokens. But when I called the get_usdt_to_egld() like this: mxpy --verbose contract call erd1qqqqqqqqqqqqqpgq027dusnhgjug07pwzhdaqv0sxt7j0hsn2nfsww256n --chain D --pem="../walletKey.pem" --gas-limit=2000000 --function="get_usdt_to_egld" --arguments 1000 --proxy="https://devnet-gateway.multiversx.com" --recall-nonce --send my transaction get failed, see the transaction here: https://devnet-explorer.multiversx.com/transactions/bae86eec15ce3a3a6aac39447bd3d7a6f4197b98b448b5188ea0bc8756b4369a#decimal.

And when I queried like this: mxpy contract query erd1qqqqqqqqqqqqqpgq027dusnhgjug07pwzhdaqv0sxt7j0hsn2nfsww256n --proxy="https://devnet-gateway.multiversx.com" --function="get_usdt_to_egld" --arguments 10000 I got this error:

RuntimeError: Query failed: invalid contract code (not found)

What I want to do? => I want to implement the logic:

  1. I minted my token and funded the contract with that token. Price of my token is 0.005 USDT
  2. I want user will enter the amount of token they want to buy in buy_token().
  3. Now in buy_token() the amount(given by user) will be multiplied by 500 as USDT has 6 decimal. So we will get the price of total amount of token in USDT.
  4. Then I wanna use the exchange to get the price of those tokens ( which are now in USDT form )
    in EGLD.
  5. After getting the EGLD value i will put a require statement where the condition will be egld_value() should be equal to the EGLD value we got.
  6. Then we will transfer the amount of token to user wallet.

This is what i want to implement. Help me to implement it.

1

There are 1 best solutions below

0
Sorin Ionut On

I know it must probably be a late answer, but maybe it will help other developers. The way we can query the price of the token has changed a bit in the last few months, as we are now able to do so using the Safe Price query SC.

You can take a look at the following code in the exchange repo. Here you can see all the available view functions for fetching the price of a specific token, based on the price inside the LP. They allow you a wide range of options, from providing a specific timeframe for the price query, compute the price using the default parameters or even obtaining the safe price for both tokens in the LP, among others.

https://github.com/multiversx/mx-exchange-sc/blob/main/dex/pair/src/safe_price_view.rs

Now, the way you integrate the Safe Price query SC in your contract is by making a proxy call to the generic contract, which allows you to provide the desired pair address from where you want to fetch the price. Basically, one query address for all the pair contracts.

Following your example, where you want to query the price of WEGLD, by providing a stable token input amount, the implementation would like something like:

let wegld_price: EsdtTokenPayment = self
        .pair_proxy(price_query_address)
        .get_safe_price_by_default_offset(
            stable_pair_address,
            EsdtTokenPayment::new(stable_token_id, 0, stable_worth_amount),
        )
        .execute_on_dest_context();

Hope this helps clarify things when implementing a Safe Price logic in your contract.