1

I am facing an issue while creating a DEX pallet that allows a user to create a their tokens contract and add it to my DEX in a Substrate-based node. I am using the substrate-node-contract to upload the smart contract and have set up a separate node for using the DEX pallet.

contract upload enviroment

i getting the address from Contract Address in Dry-run outcome` part .

i have created two contract and add them address into the pallet dex :

pallet inputs

and i got these event results :

treasury:UpdatedInactive
["1,054,400,041,399,279","1,055,584,901,822,798"]
system:ExtrinsicFailed
[{"Module":{"index":"58","error":"0x00000000"}},{"weight":{"refTime":"1,077,859,000","proofSize":"0"},"class":"Normal","paysFee":"Yes"}]
transactionPayment:TransactionFeePaid
["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY","1,481,075,529,399","0"]
balances:Deposit
["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY","296,215,105,880"]
treasury:Deposit
["1,184,860,423,519"]
balances:Deposit
["5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z","1,184,860,423,519"]
balances:Withdraw
["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY","1,481,075,529,399"]

now when i need to check the assets have stored into the storage or not . it show me nothing .

result

i want to know whats the problem ? how can store the assets into the storage ?

this is my code :

    #![cfg_attr(not(feature = "std"), no_std)]

pub mod weights;

use frame_support::traits::Currency;
use sp_std::prelude::*;

pub use pallet::*;
pub use weights::WeightInfo;

type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
type BalanceOf<T> = <<T as Config>::Currency as Currency<AccountIdOf<T>>>::Balance;
type AssetIdOf<T> = <T as Config>::AssetId;
type AssetBalanceOf<T> = <T as Config>::AssetBalance;

#[frame_support::pallet]
pub mod pallet {
    use super::*;
    use codec::EncodeLike;
    use frame_support::{
        pallet_prelude::*,
        sp_runtime::{
            traits::{
                AccountIdConversion, CheckedAdd, CheckedMul, CheckedSub, Convert, One, Saturating,
                Zero,
            },
            FixedPointNumber, FixedPointOperand, FixedU128,
        },
        traits::{
            fungibles::{Create, Destroy, Inspect, Mutate, Transfer},
            tokens::{Balance, WithdrawConsequence},
            ExistenceRequirement,
        },
        transactional, PalletId,
    };
    use frame_system::{pallet_prelude::*, Origin};
    use sp_std::fmt::Debug;

    #[pallet::pallet]
    #[pallet::generate_store(pub(super) trait Store)]
    pub struct Pallet<T>(_);

    #[pallet::config]
    pub trait Config: frame_system::Config {
        /// Pallet ID.
        #[pallet::constant]
        type PalletId: Get<PalletId>;

        /// The overarching event type.
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

        /// The currency trait.
        type Currency: Currency<Self::AccountId>;

        /// The balance type for assets (i.e. tokens).
        type AssetBalance: Balance
            + FixedPointOperand
            + MaxEncodedLen
            + MaybeSerializeDeserialize
            + TypeInfo;

        // Two-way conversion between asset and currency balances
        type AssetToCurrencyBalance: Convert<Self::AssetBalance, BalanceOf<Self>>;
        type CurrencyToAssetBalance: Convert<BalanceOf<Self>, Self::AssetBalance>;

        /// The asset ID type.
        type AssetId: MaybeSerializeDeserialize
            + MaxEncodedLen
            + TypeInfo
            + Clone
            + Debug
            + PartialEq
            + EncodeLike
            + Decode;

        /// The type for tradable assets.
        type Assets: Inspect<Self::AccountId, AssetId = Self::AssetId, Balance = Self::AssetBalance>
            + Transfer<Self::AccountId>;

        /// The type for liquidity tokens.
        type AssetRegistry: Inspect<Self::AccountId, AssetId = Self::AssetId, Balance = Self::AssetBalance>
            + Mutate<Self::AccountId>
            + Create<Self::AccountId>
            + Destroy<Self::AccountId>;

        /// Information on runtime weights.
        type WeightInfo: WeightInfo;

        /// Provider fee numerator.
        #[pallet::constant]
        type ProviderFeeNumerator: Get<BalanceOf<Self>>;

        /// Provider fee denominator.
        #[pallet::constant]
        type ProviderFeeDenominator: Get<BalanceOf<Self>>;

        /// Minimum currency deposit for a new exchange.
        #[pallet::constant]
        type MinDeposit: Get<BalanceOf<Self>>;
    }

    #[pallet::storage]
    #[pallet::getter(fn something)]
    pub type Something<T> = StorageValue<_, u32>;

    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        /// A new exchange was created [asset_id, liquidity_token_id]
        ExchangeCreated(AssetIdOf<T>, AssetIdOf<T>),
        /// Liquidity was added to an exchange [provider_id, asset_id, currency_amount,
        /// token_amount, liquidity_minted]
        LiquidityAdded(
            T::AccountId,
            AssetIdOf<T>,
            BalanceOf<T>,
            AssetBalanceOf<T>,
            AssetBalanceOf<T>,
        ),
        /// Liquidity was removed from an exchange [provider_id, asset_id, currency_amount,
        /// token_amount, liquidity_amount]
        LiquidityRemoved(
            T::AccountId,
            AssetIdOf<T>,
            BalanceOf<T>,
            AssetBalanceOf<T>,
            AssetBalanceOf<T>,
        ),
        /// Currency was traded for an asset [asset_id, buyer_id, recipient_id, currency_amount,
        /// token_amount]
        CurrencyTradedForAsset(
            AssetIdOf<T>,
            T::AccountId,
            T::AccountId,
            BalanceOf<T>,
            AssetBalanceOf<T>,
        ),
        /// An asset was traded for currency [asset_id, buyer_id, recipient_id, currency_amount,
        /// token_amount]
        AssetTradedForCurrency(
            AssetIdOf<T>,
            T::AccountId,
            T::AccountId,
            BalanceOf<T>,
            AssetBalanceOf<T>,
        ),
    }

    #[pallet::error]
    pub enum Error<T> {
        /// Asset with the specified ID does not exist
        AssetNotFound,
        /// Exchange for the given asset already exists
        ExchangeAlreadyExists,
        /// Provided liquidity token ID is already taken
        TokenIdTaken,
        /// Not enough free balance to add liquidity or perform trade
        BalanceTooLow,
        /// Not enough tokens to add liquidity or perform trade
        NotEnoughTokens,
        /// Specified account doesn't own enough liquidity in the exchange
        ProviderLiquidityTooLow,
        /// No exchange found for the given `asset_id`
        ExchangeNotFound,
        /// Zero value provided for trade amount parameter
        TradeAmountIsZero,
        /// Zero value provided for `token_amount` parameter
        TokenAmountIsZero,
        /// Zero value provided for `max_tokens` parameter
        MaxTokensIsZero,
        /// Zero value provided for `currency_amount` parameter
        CurrencyAmountIsZero,
        /// Value provided for `currency_amount` parameter is too high
        CurrencyAmountTooHigh,
        /// Value provided for `currency_amount` parameter is too low
        CurrencyAmountTooLow,
        /// Zero value provided for `min_liquidity` parameter
        MinLiquidityIsZero,
        /// Value provided for `max_tokens` parameter is too low
        MaxTokensTooLow,
        /// Value provided for `min_liquidity` parameter is too high
        MinLiquidityTooHigh,
        /// Zero value provided for `liquidity_amount` parameter
        LiquidityAmountIsZero,
        /// Zero value provided for `min_currency` parameter
        MinCurrencyIsZero,
        /// Zero value provided for `min_tokens` parameter
        MinTokensIsZero,
        /// Value provided for `min_currency` parameter is too high
        MinCurrencyTooHigh,
        /// Value provided for `min_tokens` parameter is too high
        MinTokensTooHigh,
        /// Value provided for `max_currency` parameter is too low
        MaxCurrencyTooLow,
        /// Value provided for `min_bought_tokens` parameter is too high
        MinBoughtTokensTooHigh,
        /// Value provided for `max_sold_tokens` parameter is too low
        MaxSoldTokensTooLow,
        /// There is not enough liquidity in the exchange to perform trade
        NotEnoughLiquidity,
        /// Overflow occurred
        Overflow,
        /// Underflow occurred
        Underflow,
        /// Deadline specified for the operation has passed
        DeadlinePassed,
    }

    pub trait ConfigHelper: Config {
        fn pallet_account() -> AccountIdOf<Self>;
        fn currency_to_asset(curr_balance: BalanceOf<Self>) -> AssetBalanceOf<Self>;
        fn asset_to_currency(asset_balance: AssetBalanceOf<Self>) -> BalanceOf<Self>;
        fn net_amount_numerator() -> BalanceOf<Self>;
    }

    impl<T: Config> ConfigHelper for T {
        #[inline(always)]
        fn pallet_account() -> AccountIdOf<Self> {
            Self::PalletId::get().into_account_truncating()
        }

        #[inline(always)]
        fn currency_to_asset(curr_balance: BalanceOf<Self>) -> AssetBalanceOf<Self> {
            Self::CurrencyToAssetBalance::convert(curr_balance)
        }

        #[inline(always)]
        fn asset_to_currency(asset_balance: AssetBalanceOf<Self>) -> BalanceOf<Self> {
            Self::AssetToCurrencyBalance::convert(asset_balance)
        }

        #[inline(always)]
        fn net_amount_numerator() -> BalanceOf<Self> {
            Self::ProviderFeeDenominator::get()
                .checked_sub(&Self::ProviderFeeNumerator::get())
                .expect("Provider fee shouldn't be greater than 100%")
        }
    }

    #[derive(
        Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, MaxEncodedLen, TypeInfo,
    )]
    pub struct Exchange<AssetId, Balance, AssetBalance> {
        pub asset_id: AssetId,
        pub currency_reserve: Balance,
        pub token_reserve: AssetBalance,
        pub liquidity_token_id: AssetId,
    }

    type ExchangeOf<T> = Exchange<AssetIdOf<T>, BalanceOf<T>, AssetBalanceOf<T>>;

    #[pallet::storage]
    #[pallet::getter(fn exchanges)]
    pub(super) type Exchanges<T: Config> =
        StorageMap<_, Twox64Concat, AssetIdOf<T>, ExchangeOf<T>, OptionQuery>;

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        #[pallet::call_index(0)]
        #[pallet::weight(<T as Config>::WeightInfo::create_exchange())]
        #[transactional]
        pub fn create_exchange(
            origin: OriginFor<T>,
            asset_id: AssetIdOf<T>,
            liquidity_token_id: AssetIdOf<T>,
            currency_amount: BalanceOf<T>,
            token_amount: AssetBalanceOf<T>,
        ) -> DispatchResult {
            // -------------------------- Validation part --------------------------
            let caller = ensure_signed(origin)?;
            ensure!(currency_amount >= T::MinDeposit::get(), Error::<T>::CurrencyAmountTooLow);
            ensure!(token_amount > Zero::zero(), Error::<T>::TokenAmountIsZero);
            if T::Assets::total_issuance(asset_id.clone()).is_zero() {
                Err(Error::<T>::AssetNotFound)?
            }
            if <Exchanges<T>>::contains_key(asset_id.clone()) {
                Err(Error::<T>::ExchangeAlreadyExists)?
            }

            // ----------------------- Create liquidity token ----------------------
            T::AssetRegistry::create(
                liquidity_token_id.clone(),
                T::pallet_account(),
                false,
                <AssetBalanceOf<T>>::one(),
            )
            .map_err(|_| Error::<T>::TokenIdTaken)?;

            // -------------------------- Update storage ---------------------------
            let exchange = Exchange {
                asset_id: asset_id.clone(),
                currency_reserve: <BalanceOf<T>>::zero(),
                token_reserve: <AssetBalanceOf<T>>::zero(),
                liquidity_token_id: liquidity_token_id.clone(),
            };
            let liquidity_minted = T::currency_to_asset(currency_amount);
            Self::do_add_liquidity(
                exchange,
                currency_amount,
                token_amount,
                liquidity_minted,
                caller,
            )?;

            // ---------------------------- Emit event -----------------------------
            Self::deposit_event(Event::ExchangeCreated(asset_id, liquidity_token_id));
            Ok(())
        }
    }

    impl<T: Config> Pallet<T> {
        /// Perform currency and asset transfers, mint liquidity token,
        /// update exchange balances, emit event
        #[transactional]
        fn do_add_liquidity(
            mut exchange: ExchangeOf<T>,
            currency_amount: BalanceOf<T>,
            token_amount: AssetBalanceOf<T>,
            liquidity_minted: AssetBalanceOf<T>,
            provider: AccountIdOf<T>,
        ) -> DispatchResult {
            let asset_id = exchange.asset_id.clone();
            let pallet_account = T::pallet_account();

            <T as pallet::Config>::Currency::transfer(
                &provider,
                &pallet_account,
                currency_amount,
                ExistenceRequirement::KeepAlive,
            )?;

            T::Assets::transfer(asset_id.clone(), &provider, &pallet_account, token_amount, true);
            T::AssetRegistry::mint_into(
                exchange.liquidity_token_id.clone(),
                &provider,
                liquidity_minted,
            )?;

            exchange.currency_reserve.saturating_accrue(currency_amount);
            exchange.token_reserve.saturating_accrue(token_amount);
            <Exchanges<T>>::insert(asset_id.clone(), exchange);

            Self::deposit_event(Event::LiquidityAdded(
                provider,
                asset_id,
                currency_amount,
                token_amount,
                liquidity_minted,
            ));

            Ok(())
        }
    }
}

2 Answers 2

2

I think that your understanding is a bit off here. For create_exchange you need to pass an AssetId as parameter, which is native to the runtime (i.e. pallet-assets), not a smart contract.

7
  • Please guide me. i want add token in my pallet . for example user wants add KCC token and use have to use smart contract address . is it write ?
    – Mr Coder
    Mar 28, 2023 at 16:37
  • You can create a token through pallet-assets here. Mar 29, 2023 at 7:51
  • You mean i dont need use smart contract?
    – Mr Coder
    Mar 29, 2023 at 8:01
  • If you want to use this dex-pallet you have to create a token through pallet-assets Mar 29, 2023 at 8:10
  • What should i do if i want to let user create their tokens by smart contract and allow them to add their tokens in dex-pallet ?
    – Mr Coder
    Mar 29, 2023 at 8:18
2

A possible misunderstanding here could be that you think the dry-run has any effect. You linked this screenshot:

enter image description here

The dry-run here doesn't actually result in any effect on-chain, it's purely a preview of what would happen if you press "Next".

So if you haven't done, you actually need to submit this transaction (via "Next") to have any storage mutations persisted on-chain.

1
  • i have put this screenshot for say to the developers that are trying to help me , i get smart contract address in this step .
    – Mr Coder
    Mar 28, 2023 at 16:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.