---
# System prepended metadata

title: Pallet Decoupling

---

# Pallet Decoupling

## Why decoupling
- Verbosity
- Readability
- Debug
- Maintainability
- ...

## Coupled Way

Example:
```rust=
// Definition
pub trait Trait: frame_sysmte::Trait + module1::Trait + module2::Trait + ... {
   type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
   ...
}

// usage
{
   ...
   // read storages
   let module1_value = <module1::ModuleStorage1<T>>::get(key1);
   let module2_value = <module2::ModuleStorage2<T>>::get(key2);
   // write storages
   <module1::ModuleStorage1<T>>::mutate(&key1, |val| {
       // some change here
   });
   <module2::ModuleStorage2<T>>::mutate(&key2, |val| {
       // some change here
   });
   ...
}
```

And you have to import module1 and module2 to your current cargo.toml.
```toml
module1 = { path = ".." }
module2 = { path = ".." }
```

## How to decouple

### Senario: 
There's a pallet named `Exchange` that wants to read/write pallet `Token`’s storage.

`Token` has a storage:
```rust=
decl_storage! {
    trait Store for Module<T: Trait> as Token {
        pub AccountToken get(fn token): map hasher(blake2_128_concat) (T::AccountId, Symbol) => Token;
    }
}
```

1. Define a trait(Better do define it in a crate only execept `Token`)
```rust=
pub trait TokenTrait<AccountId> {
   fn decrease(who: &AccountId, symbol: Symbol, amount: u128);
   fn increase(who: &AccountId, symbol: Symbol, amount: u128);
   fn get_token(who: &AccountId, symbol: Symbol) -> Token;
   fn has_token(who: &AccountId, symbol: Symbol) -> bool;
}
```
2. Impl this trait for module `Token`
```rust=
// impl this trait for others module can access and modyfy token'data
impl<T: Trait> token_primitives::TokenTrait<T::AccountId> for Module<T> {
   fn decrease(who: &T::AccountId, symbol: Symbol, amount: u128) {
       <AccountToken<T>>::mutate((who, symbol), |token| {
           token.balance = token.balance.saturating_sub(amount);
       });
   }

   fn increase(who: &T::AccountId, symbol: Symbol, amount: u128) {
       <AccountToken<T>>::mutate((who, symbol), |token| {
           token.balance = token.balance.saturating_add(amount);
       });
   }

   fn get_token(who: &T::AccountId, symbol: Symbol) -> Token {
       <AccountToken<T>>::get((who, symbol))
   }

   fn has_token(who: &T::AccountId, symbol: Symbol) -> bool {
       <AccountToken<T>>::contains_key((who, symbol))
   }
}
```
3. Register a trait handler for module `Exchange`.
```rust=
use token_primitives::{Symbol, TokenTrait};

pub trait Trait: frame_system::Trait {
   type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
  
   /// Token trait handler
   type TokenTrait: TokenTrait<Self::AccountId>;
}

// usage
ensure!(
    T::TokenTrait::has_token(&exchanger, exchange_symbol) && T::TokenTrait::has_token(&exchanger, target_symbol),
    Error::<T>::UserHasNoThisToken
);
ensure!(
    T::TokenTrait::get_token(&exchanger, exchange_symbol).balance >= amount,
    Error::<T>::ExchangeTooMuch
);
```

4. Connect them in runtime
```rust=
// configure token for runtime
impl token::Trait for Runtime {
   type Event = Event;
}

// configure token exchange for runtime
impl token_exchange::Trait for Runtime {
   type Event = Event;
   type TokenTrait = Token; // this is the key for decoupling modules
}

construct_runtime!(
   pub enum Runtime where
       Block = Block,
       NodeBlock = node_primitives::Block,
       UncheckedExtrinsic = UncheckedExtrinsic
   {
        …
       // construct token and exchange fo runtime
       Token: token::{Pallet, Call, Storage, Event<T>},
       TokenExchange: token_exchange::{Pallet, Call, Storage, Event<T>},
     }
);
```
