# Welcome

Welcome to Sentre, the All-in-One Solana Open Platform with DApps Store and Universal Protocol for Liquidity.

:hand\_splayed:Hello Sentizens, <https://hub.sentre.io>

## Sentre in the first look

The first time of learning about Sen, you may be a bit confused amount Sentre, SenHub, and SenSwap. By the below explanation, we hope that we can make it clear to you:

* **Sentre** refers to the whole ecosystem, including everything such as SenSwap, SenHub, etc.
* **SenHub** is a platform that offers a base for blockchain developers to quickly build and ship decentralized applications (DApps) to users.

## Individual development is hard

If you are an individual developer and you're incubating an innovative idea, there are several things you need to do before success. [UniSwap](https://uniswap.org/) needed 2 years to bring their idea to people. [Compound](https://compound.finance/) had a talented team but also spent more than a year to launch the product.

{% hint style="danger" %}
:hourglass\_flowing\_sand: You have to spend a lot of unexpected time to realize your ideas.
{% endhint %}

After a long time of struggling with code on your local machine, you - an individual developer - need to rent servers, buy domains, subscribe to many third services just for an official launch. That may consume a lot of money.

{% hint style="danger" %}
:money\_with\_wings: You have to spend money on expensive services.
{% endhint %}

Furthermore, you have to do some marketing stuff that's even beyond the endurance of a geek. It's obvious that the process is very challenging and likely failed.

{% hint style="danger" %}
:exploding\_head: You have to do many things that aren't your strength.
{% endhint %}

In the end, the final evil is liquidity. If you build a DeFi protocol, liquidity is essential to run your protocol. Your idea may be never known by the public because of a lack of liquidity.

{% hint style="danger" %}
:droplet: Liquidity is a very limited resource for a new protocol.
{% endhint %}

## Sentre leverages innovative ideas

Thus, Sentre aims to solve a solution to help developers tackle these challenges and encourage innovation. A developer can:

* [x] Quickly develop a DApp by several provided libraries by SenOS.
* [x] Be a native application in Sentre.
* [x] Instantly approach a large number of users.
* [x] Inherit liquidity from primary services in Sentre.
* [x] Not to pay for Sen services.


# Getting Started

## Prerequisite

```
Node: v16.15.0
Git: 2.30.1
```

## Create a new project

{% hint style="info" %}
**Prerequisite**: NodeJS, Git

**Optional for better development:** Redux Devtool\* (Chrome extension), Prettier\*\* (Editor Extension)

*\* Redux Devtool is optional, but it's very helpful to follow the application's states.*

*\*\* Prettier helps you maintain a consistent code style*
{% endhint %}

To create a new `my-app` project, you can conveniently create one by [create-senhub-app](https://www.npmjs.com/package/create-senhub-app).

```shell
npx create-senhub-app init my-app
```

Or,

```
yarn create senhub-app init my-app
```

Add this moment you can immediately start the project by `yarn start`, but we highly recommend following the next steps to be able to host your Dapp and submit it to the Sentre platform.

## Push the project on Github

Because the platform only supports **Github** currently, you have to host your repo; and your DApp later on; on **Github**.

Choose the **New** button to create a new repository.

![Choose New to create a new repository.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F2yDpwM4utR6qLf7RyHm5%2FScreen%20Shot%202021-11-21%20at%2014.54.24.png?alt=media\&token=b36e0daa-c0a8-4fb5-a0d2-35e7762ebd5a)

Fill in the repository name, then click **Create repository**.

![Enter the project's name.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FnQE2rjumbAvQ3PpzCz6o%2FScreen%20Shot%202021-11-21%20at%2014.58.57.png?alt=media\&token=412ca2bf-92e4-451c-8a3e-e600b6d7ae6e)

After the successful creation, you will see something necessary to connect your local project to the repository.

![Information to connect.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FOji6bAqJ8pFzv1gbJmyG%2FScreen%20Shot%202021-11-21%20at%2015.03.44.png?alt=media\&token=5ce1dccb-3add-414e-9248-51ffc40a3e1b)

Follow the second section in the info with additional commands to connect to the local project. For example:

```
cd ./my-app
git init
git remote add origin git@github.com:tuphan-dn/my-app.git
git branch -M master
git add .
git commit -m "first commit"
git push -u origin master
```

## Start

Now you can start the project:

```shell
yarn start
```


# DApp Manifest

In the root folder `./my-app`, you can declare your application info by changing default values in `.env.local`. Let's say we will change it like this:

#### .env.local

```
PORT=3000
APP_ID=my_app
APP_NAME=My App
AUTHOR_NAME=Sentre
AUTHOR_EMAIL=hi@sentre.io
TAGS=solana,dapps
DESCRIPTION=A DApp Example
GITHUB=https://tuphan-dn.github.io/my-app
```

{% hint style="warning" %}
Please replace all `tuphan-dn` by your username or organization name on Github.
{% endhint %}

| Property      | Description                                                                                                                                                                                                                                           |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PORT          | The port of local hosting. For example, your development host would be <http://localhost:3000> if the PORT=3000.                                                                                                                                      |
| APP\_ID       | A unique identity for the DApp. It's must strictly follow the APP\_NAME. The APP\_ID is the lowercase of APP\_NAME with all spaces being replaced by underscores. For example, the APP\_NAME **My App** will be converted to **my\_app** for APP\_ID. |
| APP\_NAME     | The DApp's name, which is used to infer the APP\_ID.                                                                                                                                                                                                  |
| AUTHOR\_NAME  | The author's name. It's could be an individual name or organization name.                                                                                                                                                                             |
| AUTHOR\_EMAIL | The author's email.                                                                                                                                                                                                                                   |
| TAGS          | Related categories, tags for the DApp. Each will be separated by commas.                                                                                                                                                                              |
| DESCRIPTION   | A short description of the DApp.                                                                                                                                                                                                                      |
| GITHUB        | Github Pages url of the DApp.                                                                                                                                                                                                                         |

#### For submission

```
npx create-senhub-app manifest
```

A full manifest for your DApp will be generated in the root folder. You can use it to submit your DApp. See [Submitting DApps](/submitting-dapps) for details.


# Folder Structure

## The ./src

```
.
├── configs
├── model
├── shared
├── static
├── view
├── bootstrap.app.tsx
├── bootstrap.tsx
└── static.app.tsx
```

For casual development, focusing on `./src` is barely enough to build a DApp. You may create, rename, or delete any files or directories in this folder for your favorite structure. However, to let the mother platform could recognize your DApps, you MUST keep 2 files namely `bootstrap.app.tsx` and `static.app.tsx`.

The template is built for React + Redux development. Changing to another stack requires a deep understanding of Module Federation and Micro Frontend, which is not recommended. The stack of React + Redux is pretty easy to learn and strong for state management.

## The others

**./public:** The project entrypoint.

**./env.\*:** The set of environment configs.

**./\*.config.js:** Build-time and run-time configs.

**./.github:** The Git Action definition


# Available Scripts

👉 create-senhub-app CLI: https\://github.com/DescartesNetwork/sen-core/blob/master/packages/create-senhub-app/README.md

## New projects (via [create-senhub-app](https://github.com/DescartesNetwork/sen-core/blob/master/packages/create-senhub-app/README.md))

```
npx create-senhub-app init <your_project_name>
```

## Start

```
yarn start // Start development server
```

## Manifest

```
npx create-senhub-app manifest // Build a manifest file
```

## Advances

```
yarn deploy // Manually redeploy remote resources
yarn test // React test
yarn build // Production build only
```


# Development


# View

The DApp's appearance

In the view, your DApp will occupy the whole viewpoint of the device; except the header of the system. You have a full right to customize it by owned style.

![The page view](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FbyiJpsapkeHFz7bIJZGE%2F1.png?alt=media\&token=c47f5a63-de84-4a59-b93f-21fcee8fc21c)

To implement the view, the code will be placed in `./src/view` and declared by the file `./src/bootstrap.app.tsx` .

```typescript
// ./src/bootstrap.app.tsx

import { Provider } from 'react-redux'
import { UIProvider } from '@sentre/senhub'

import View from 'view'

import model from 'model'
import configs from 'configs'

const {
  manifest: { appId },
} = configs

export const Page = () => {
  return (
    <UIProvider appId={appId} antd>
      <Provider store={model}>
        <View />
      </Provider>
    </UIProvider>
  )
}

export * from 'static.app'
```

In the template, you can see that the `View` is exported with context providers (see [Providers](/development/providers)). Also, static files declared in `static.app.tsx` is exported here too. The structure in the `bootstrap.app.tsx` is compulsory for DApp recognition.


# Model & Controllers

Cook and manage DApp's states by Redux Toolkit.

> ### Single model - Multiple controllers

## Model

Typically, the model always has a single file that is to merge all the controllers' states into the store.

```typescript
// model/index.ts

import { configureStore } from '@reduxjs/toolkit'
import { devTools, bigintSerializationMiddleware } from 'shared/devTools'

import main from 'app/model/main.controller'

/**
 * Isolated store
 */
const model = configureStore({
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware(bigintSerializationMiddleware),
  devTools: devTools(process.env.REACT_APP_ID as string),
  reducer: {
    main,
  },
})

export type AppState = ReturnType<typeof model.getState>
export type AppDispatch = typeof model.dispatch
export default model
```

Following the template, your DApp's state is isolated in a store named `myapp`. If you installed Redux Devtool, you are able to inspect the `myapp` states clearly.

![The isolated states of myapp.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FzskpzhyymFh6yoAT5oKX%2FScreen%20Shot%202021-11-22%20at%2000.31.38.png?alt=media\&token=e2bf1bc6-8197-4f8b-a637-a0e7784923e2)

Additionally, the model will merge all states in `reducer` (i.e. `main` is the current state declared in the reducer) which are exported from controllers. To import a new state, you merely need to add the state into the reducer.

## Controllers

Controllers typically are to fetch raw data, process it to good forms, and export it to the model.

```typescript
// main.controller.ts

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'

/**
 * Interface & Utility
 */

export type State = {
  counter: number
}

/**
 * Store constructor
 */

const NAME = 'main'
const initialState: State = {
  counter: 0,
}

/**
 * Actions
 */

export const increaseCounter = createAsyncThunk<State, void, { state: any }>(
  `${NAME}/increaseCounter`,
  async (_, { getState }) => {
    const {
      main: { counter },
    } = getState()
    return { counter: counter + 1 }
  },
)

/**
 * Usual procedure
 */

const slice = createSlice({
  name: NAME,
  initialState,
  reducers: {},
  extraReducers: (builder) =>
    void builder.addCase(
      increaseCounter.fulfilled,
      (state, { payload }) => void Object.assign(state, payload),
    ),
})

export default slice.reducer
```

By the example, the name and struct of the state had been assigned at lines 15, 16. The function `increaseCounter` is to compute and return the next state partially which will mutate the current state in slice (i.e. line 38 to build a state and line 44 to catch the next state from `increaseCounter`).

{% hint style="info" %}
Examine [Best Practices](/best-practices) for more examples.
{% endhint %}


# Providers

The series of context providers

## \[Deprecated since senhub v4]

{% hint style="info" %}
Consider [Hooks](/advanced-usage/hooks) instead. They serve the same functionality but with better performance.
{% endhint %}

By these context providers, a DApp can easily access data that is provided by the os. The context is pretty diverse including user interface info, wallet info, blockchain data, etc.

To use a provider, you need to wrap your DApps by the provider. For example, to access the user interface info like current viewpoint, is-touchable, etc., I have to wrap the widget view into the UI Provider.

```typescript
// widget.app.tsx
// ...
const Widget = () => {
  return (
    <UIProvider appId={appId}>
      <Provider store={model}>
        <WidgetView />
      </Provider>
    </UIProvider>
  )
}
// ...
```

Then all components inside the widget view can read the user interface info like this,

```typescript
// widget/index.tsx
// ...
import { useUI } from 'senhub/providers'

const Widget = () => {
  const {
    ui: { width, infix },
  } = useUI()
}
// ...
```


# UI Provider

🌈  User Interface Provider

UIProvider is strictly required if the DApp uses default UI system of the platform, or a customized design system based on Ant Design.

## API

```tsx
<UIProvider> ... </UIProvider>
```

| Property | Type                                    | Description                                                                                                                                    | Default   |
| -------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| children | ReactNode                               | The wrapped children.                                                                                                                          | undefined |
| appId    | string                                  | DApp's id.                                                                                                                                     |           |
| style    | ?CSSPreperties                          | The additional style for `span` tags.                                                                                                          | {}        |
| antd     | ? (boolean \| FC\<ConfigProviderProps>) | Enable isolated antd. You can input the ConfigProvider as [Ant Design ConfigProvider API](https://ant.design/components/config-provider/#API). | false     |

#### For example

```tsx
import { UIProvider } from '@sentre/senhub'

// Wrap a paragraph as a child and style it to red color.
<UIProvider appId="my_app" style={{color: 'red'}}>
  <p>Hello world</p>
</UIProvider>
```

## Context

```typescript
type Provider = {
  ui: State
}

type State = {
  theme: 'light' | 'dark'
  width: number
  infix: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
  touchable: boolean
  visibleActionCenter: boolean
}
```

#### Provider

| Property | Type  | Description              |
| -------- | ----- | ------------------------ |
| ui       | State | The user interface data. |

#### State

| Property            | Type                              | Description                           |
| ------------------- | --------------------------------- | ------------------------------------- |
| theme               | light \| dark                     | Current theme mode.                   |
| width               | number                            | Current width of screen.              |
| infix               | xs \| sm \| md \| lg \| xl \| xxl | Current breakpoint of screen.         |
| touchable           | boolean                           | Whether or not touch screen.          |
| visibleActionCenter | boolean                           | Whether or not visible action center. |

## Hook & HOC

```typescript
import { useUI, withUI } from '@senhub/providers'
```

#### For example

{% hint style="info" %}
Wrap the parent by UIProvider before accessing the context.
{% endhint %}

```tsx
import { useUI, withUI } from '@senhub/providers'

// Within a functional component
const Component = () => {
  const {
    ui: { width, infix },
  } = useUI()
}
export default Component

// Within a class component
class Component {
  render() {
    const {
      ui: { width, infix },
    } = this.props
  }
}
export default withUI(Component)
```


# Wallet Provider

💳  Connecting Wallet Provider

## API

```tsx
<WalletProvider> ... </WalletProvider>
```

| Property | Type      | Description           | Default   |
| -------- | --------- | --------------------- | --------- |
| children | ReactNode | The wrapped children. | undefined |

#### For example

```tsx
import { WalletProvider } from '@senhub/provider'

// Wrap a paragraph as a child.
<WalletProvider>
  <p>Hello world</p>
</WalletProvider>
```

## Context

```typescript
type Provider = {
  wallet: State
}

type State = {
  visible: boolean
  address: string
  lamports: bigint
}
```

#### Provider

| Property | Type  | Description      |
| -------- | ----- | ---------------- |
| wallet   | State | The wallet data. |

#### State

| Property | Type    | Description                                                                              |
| -------- | ------- | ---------------------------------------------------------------------------------------- |
| visible  | boolean | Whether the wallet modal is visible.                                                     |
| address  | string  | The connecting wallet address.                                                           |
| lamports | bigint  | The available number of lamports (1 SOL = 1,000,000,000 lamports) in the current wallet. |

## Hook & HOC

```typescript
import { useWallet, withWallet } from '@senhub/providers'
```

#### For example

{% hint style="info" %}
Wrap the parent by WalletProvider before accessing the context.
{% endhint %}

```tsx
import { useWallet, withWallet } from '@senhub/providers'

// Within a functional component
const Component = () => {
  const {
    wallet: { address, lamports },
  } = useWallet()
}
export default Component

// Within a class component
class Component {
  render() {
    const {
      wallet: { address, lamports },
    } = this.props
  }
}
export default withWallet(Component)
```


# Account Provider

🏦  SPL Accounts Provider

## API

```tsx
<AccountProvider> ... </AccountProvider>
```

| Property | Type      | Description           | Default   |
| -------- | --------- | --------------------- | --------- |
| children | ReactNode | The wrapped children. | undefined |

#### For example

```tsx
import { AccountProvider } from '@sentre/senhub'

// Wrap a paragraph as a child.
<AccountProvider>
  <p>Hello world</p>
</AccountProvider>
```

## Context

```typescript
type Provider = {
  accounts: State
}

type State = Record<string, AccountData>
type AccountData = {
  mint: string;
  owner: string;
  amount: bigint;
  delegate_option: number;
  delegate: string;
  state: number;
  is_native_option: number;
  is_native: bigint;
  delegated_amount: bigint;
  close_authority_option: number;
  close_authority: string;
}
```

#### Provider

| Property | Type                         | Description                                                          |
| -------- | ---------------------------- | -------------------------------------------------------------------- |
| accounts | Record\<string, AccountData> | A mapping from an account address to the corresponding account data. |

#### AccountData

| Property                 | Type        | Description                                         |
| ------------------------ | ----------- | --------------------------------------------------- |
| mint                     | string      | The corresponding mint address to the account.      |
| owner                    | string      | The account owner address.                          |
| amount                   | bigint      | The number of tokens.                               |
| delegate\_option         | 0 \| 1      | Whether the delegate property is available.         |
| delegate                 | string      | The delegate address.                               |
| delegated\_amount        | bigint      | The number of delegated tokens.                     |
| state                    | 0 \| 1 \| 2 | 0: Uninitialized; 1: Initialized; 2: Frozen;        |
| is\_native\_option       | 0 \| 1      | Whether the is\_native property is available.       |
| is\_native               | bigint      | The number of wrapped lamports.                     |
| close\_authority\_option | 0 \| 1      | Whether the close\_authority property is available. |
| close\_authority         | string      | The close authority address.                        |

## Hook & HOC

```typescript
import { useAccount, withAccount } from '@senhub/providers'
```

#### For example

{% hint style="info" %}
Wrap the parent by AccountProvider before accessing the context.
{% endhint %}

```tsx
import { useAccount, withAccount } from '@senhub/providers'

// Within a functional component
const Component = () => {
  const { accounts } = useAccount()
  console.log(accounts['8kGbKrvS3zopf4ZJwNDhEKMbZ3iC4Jztn43MZ8Nabcxq'])
  // mint: "sRHC8De9nks5KYQ7n2jYacsVgBKe9irc7vhpSzoAVYY"
  // owner: "8UaZw2jDhJzv5V53569JbCd3bD4BnyCfBH3sjwgajGS9"
  // amount: 10000000000000n
  // delegate_option: 0
  // delegate: "11111111111111111111111111111111"
  // state: 1
  // is_native_option: 0
  // is_native: 0
  // delegated_amount: 0n
  // close_authority_option: 0
  // close_authority: "11111111111111111111111111111111"
}
export default Component

// Within a class component
class Component {
  render() {
    const { accounts } = this.props
    console.log(accounts['8kGbKrvS3zopf4ZJwNDhEKMbZ3iC4Jztn43MZ8Nabcxq'])
    // mint: "sRHC8De9nks5KYQ7n2jYacsVgBKe9irc7vhpSzoAVYY"
    // owner: "8UaZw2jDhJzv5V53569JbCd3bD4BnyCfBH3sjwgajGS9"
    // amount: 10000000000000n
    // delegate_option: 0
    // delegate: "11111111111111111111111111111111"
    // state: 1
    // is_native_option: 0
    // is_native: 0
    // delegated_amount: 0n
    // close_authority_option: 0
    // close_authority: "11111111111111111111111111111111"
  }
}
export default withAccount(Component)
```


# Mint Provider

📘  Mint info Provider

## API

```tsx
<MintProvider> ... </MintProvider>
```

| Property | Type      | Description           | Default   |
| -------- | --------- | --------------------- | --------- |
| children | ReactNode | The wrapped children. | undefined |

#### For example

```tsx
import { MintProvider } from '@sentre/senhub'

// Wrap a paragraph as a child.
<MintProvider>
  <p>Hello world</p>
</MintProvider>
```

## Context

```typescript
type Provider {
  mints: State
  getMint: (mintAddress: string) => Promise<MintData>
  getDecimals: (mintAddress: string) => Promise<number>
  tokenProvider: TokenProvider
}

type State = Record<string, MintData>
type MintData = {
  mint_authority_option: number;
  mint_authority: string;
  supply: bigint;
  decimals: number;
  is_initialized: boolean;
  freeze_authority_option: number;
  freeze_authority: number;
}
type TokenProvider = any // See the table below
```

#### Provider

| Property      | Type                                            | Description                                                                                                                             |
| ------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| mints         | Record\<string, MintData>                       | A mapping from a mint address to the corresponding mint data.                                                                           |
| getMint       | async (mintAddress: string): Promise\<MintData> | Fetch mint data from live nodes or local cache by a mint address.                                                                       |
| getDecimals   | async (mintAddress: string): Promise\<number>   | Find decimals for the mint.                                                                                                             |
| tokenProvider | TokenProvider                                   | The mint metadata provider (i.e. logo uri, coingecko or coinmarketcap ticket). See [the TokenProvider section](#undefined) for details. |

#### MintData

| Property                  | Type    | Description                                                               |
| ------------------------- | ------- | ------------------------------------------------------------------------- |
| mint\_authority\_option   | 0 \| 1  | Whether the mint\_authority property is available.                        |
| mint\_authority           | string  | The authority address that can mint more token.                           |
| supply                    | bigint  | Total supply.                                                             |
| decimals                  | number  | Decimals.                                                                 |
| is\_initialized           | boolean | Whether the mint is initialized.                                          |
| freeze\_authority\_option | bigint  | Whether the freeze\_authority property is available.                      |
| freeze\_authority         | string  | The authority address that can freeze accounts corresponding to the mint. |

## Hook & HOC

```typescript
import { useMint, withMint } from '@senhub/providers'
```

#### For example

{% hint style="info" %}
Wrap the parent by MintProvider before accessing the context.
{% endhint %}

```tsx
import { useMint, withMint } from '@senhub/providers'

// Within a functional component
const Component = () => {
  const { mints } = useMint()
  console.log(mints['5YwUkPdXLoujGkZuo9B4LsLKj3hdkDcfP4derpspifSJ'])
  // mint_authority_option: 1
  // mint_authority: "5vHjWRc2hys4XwZkMktg35N8oALt5d1ZXYkwCXXX3JHm"
  // supply: 5000000000000000000n
  // decimals: 9
  // is_initialized: true
  // freeze_authority_option: 0
  // freeze_authority: "11111111111111111111111111111111"
}
export default Component

// Within a class component
class Component {
  render() {
    const { mints } = this.props
    console.log(mints['5YwUkPdXLoujGkZuo9B4LsLKj3hdkDcfP4derpspifSJ'])
    // mint_authority_option: 1
    // mint_authority: "5vHjWRc2hys4XwZkMktg35N8oALt5d1ZXYkwCXXX3JHm"
    // supply: 5000000000000000000n
    // decimals: 9
    // is_initialized: true
    // freeze_authority_option: 0
    // freeze_authority: "11111111111111111111111111111111"
  }
}
export default withMint(Component)
```

## TokenProvider

{% hint style="info" %}
In this document, we will use token and mint interchangeably. However, the meaning of both is the same.
{% endhint %}

Actually, tokenProvider is an instance from TokenProvider class. By the instance, you can find token metadata by its symbol or name for example. That way is more intuitive than using mint addresses.

#### TokenProvider API

| Property      | Type                                                        | Description                                                     |
| ------------- | ----------------------------------------------------------- | --------------------------------------------------------------- |
| find          | async (keyword: string, limit?: 10): Promise\<TokenInfo\[]> | Semantic search tokens. The function can search mutiple tokens. |
| findByAddress | async (addr: string): Promise\<TokenInfo \| undefined>      | Find a token by its address.                                    |
| all           | async (): Promise\<TokenInfo\[]>                            | Get all tokens.                                                 |

You can learn more data types in the original repo: <https://github.com/solana-labs/token-list>.

#### TokenInfo

```typescript
interface TokenInfo {
  readonly chainId: number;
  readonly address: string;
  readonly name: string;
  readonly decimals: number;
  readonly symbol: string;
  readonly logoURI?: string;
  readonly tags?: string[];
  readonly extensions?: TokenExtensions;
}
```

#### Example: all

```typescript
const { tokenProvier } = useMint()

const allTokenList = await tokenProvider.all()
console.log(allTokenList)
// [
//    ...,
//    {
//        address: "So11111111111111111111111111111111111111112"
//        chainId: 103
//        decimals: 9
//        extensions: {coingeckoId: "solana"}
//        logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png"
//        name: "Wrapped SOL"
//        symbol: "SOL"
//        tags: []
//    },
//    ...
// ]
```

#### Example: findByAddress

```typescript
const { tokenProvier } = useMint()

const wsol = await tokenProvider.findByAddress("So11111111111111111111111111111111111111112")
console.log(wsol)
// {
//    address: "So11111111111111111111111111111111111111112"
//    chainId: 103
//    decimals: 9
//    extensions: {coingeckoId: "solana"}
//    logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png"
//    name: "Wrapped SOL"
//    symbol: "SOL"
//    tags: []
// }
```

#### Example: find

```typescript
const { tokenProvier } = useMint()

const solRelatedTokenList = await tokenProvider.find("sol")
console.log(solRelatedTokenList)
// [
//    {
//        address: "So11111111111111111111111111111111111111112"
//        chainId: 103
//        decimals: 9
//        extensions: {coingeckoId: "solana"}
//        logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png"
//        name: "Wrapped SOL"
//        symbol: "SOL"
//        tags: []
//    },
//    {
//        address: "2rg5syU3DSwwWs778FQ6yczDKhS14NM3vP4hqnkJ2jsM"
//        chainId: 103
//        decimals: 9
//        extensions: {
//            background: "https://solana.com/static/8c151e179d2d7e80255bdae6563209f2/6833b/validators.webp"
//            website: "https://solana.com/"
//        }
//        logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2rg5syU3DSwwWs778FQ6yczDKhS14NM3vP4hqnkJ2jsM/logo.png"
//        name: "SOL stake pool"
//        symbol: "pSOL"
//        tags: []
//    },
// ]
```


# Static

Metadata for DApps

Static assets include icons, panels, readme, etc., which build your DApps appearance to users on the Sen Store and also on the user's dashboard.

```typescript
// ./src/static.app.tsx

import panel1 from 'app/static/images/panel1.png'
import panel2 from 'app/static/images/panel2.png'
import panel3 from 'app/static/images/panel3.png'

export const panels = [panel1, panel2, panel3]
export { default as logo } from 'app/static/images/logo.png'
export { default as readme } from 'app/static/docs/README.md'
```

Currently, to present a DApp, developers can use a logo, panels, and a readme.

#### Logo

The logo is used as an application icon and Window, iOS, or Android. The logo must be exported in the static file.

| Property | Spec                             |
| -------- | -------------------------------- |
| Format   | image/png, image/jpeg, image/svg |
| Ratio    | 1:1                              |

{% hint style="info" %}
We highly recommend the **size 256x256** pixels with a **60 border-radius** for Logo.
{% endhint %}

#### Panels

The panels usually appear as a slide for DApp introduction in Sen Store. The panel must be exported as an array in the static file.

| Property | Spec                             |
| -------- | -------------------------------- |
| Format   | image/png, image/jpeg, image/svg |
| Ratio    | 4:3                              |

#### Readme

The readme will give users a deep look such as introduction, guidelines, technical explanation, etc., about the DApp. The readme must be written under the format of markdown and exported in the static file.

| Property | Spec     |
| -------- | -------- |
| Format   | markdown |

{% hint style="info" %}
For [markdown quick references](https://wordpress.com/support/markdown-quick-reference/).
{% endhint %}


# Global variables

The global variables are all available in the `window` instances on browsers.

```typescript
interface Window {
  // Sentre
  sentre: {
    wallet?: import('@senswap/sen-js').WalletInterface
    lamports: import('@senswap/sen-js').Lamports
    splt: import('@senswap/sen-js').SPLT
    swap: import('@senswap/sen-js').Swap
  }
  // Utility
  notify: ({ type, description, onClick }: SentreNotification) => void
  message: ({ type, description, onClick }: SentreMessage) => void
}
```

## Global sentre

```typescript
window.sentre = {
  wallet?: import('@senswap/sen-js').WalletInterface
  lamports: import('@senswap/sen-js').Lamports
  splt: import('@senswap/sen-js').SPLT
  swap: import('@senswap/sen-js').Swap
}
```

{% hint style="info" %}
The following instances are from sen-js. See [sen-js APIs](https://descartesnetwork.github.io/sen-js/) for details.
{% endhint %}

| Property | Type                         | Description        |
| -------- | ---------------------------- | ------------------ |
| wallet   | WalletInterface \| undefined | Wallet instance.   |
| lamports | Lamports                     | Lamports instance. |
| splt     | SPLT                         | SPLT instance.     |
| swap     | Swap                         | Swap instance.     |

## Global notification

To create top-right notifications.

```typescript
window.notify = ({ type, description, onClick }: SentreNotification) => void

type SentreNotification = {
  type: 'error' | 'warning' | 'success' | 'info'
  description: string
  onClick?: () => void
}

window.message = ({ type, description, onClick }: SentreMessage) => void

type SentreMessage = {
  type: 'error' | 'warning' | 'success' | 'info' | 'loading'
  description: string
  onClick?: () => void
}
```

#### API

| Property    | Type                                           | Description                                                               |
| ----------- | ---------------------------------------------- | ------------------------------------------------------------------------- |
| type        | error \| warning \| success \| info \| loading | The notification type.                                                    |
| description | string                                         | The notification message.                                                 |
| onClick     | function \| undefined                          | The action that is activated when users click to the notification pop-up. |

#### Examples

```typescript
// To pop an error message on Coin98 connection failure
window.message({
  type: 'error',
  description: 'Coin98 Wallet is not connected.',
})

// To pop an warning notification on Phantom installation and direct to Phantom homepage
window.notify({
  type: 'warning',
  description: 'Phantom Wallet is not installed.',
  onClick: () => window.open('https://phantom.app/', '_blank'),
})
```


# Configs

Config for multiple runtime environments and multiple Solana networks.

In the template, the app has already had a manifest config which is to determine the DApp's id, DApp's url based on the runtime environment. For example, the DApp's url is `localhost` in the development environment, however, it will be your [Github Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages) in the production environment.

There are 2 methods to classify you configs. One is based on the runtime environment namely `development` and `production`. The other is based on the Solana network namely `devnet`, `testnet`, and `mainnet`.

## Runtime Environment

```typescript
import { env } from '@sentre/senhub'

// development -> npm start
// production -> npm run build
```

## Solana Network

```typescript
import { net, chainId } from '@sentre/senhub'

// devnet | testnet | mainnet
// 103 | 102 | 101
```


# Advanced Usage


# Theme

Light & Dark mode.

## How does it work?

The approach of light/dark theme in Sentre is pretty forward. We employ CSS Selector to realize the theme switch with pure css (or sass, less).

The current theme will be depicted by the body id. For example, the current theme is light, then `<body id="light"/>`. By contrast, `<body id="dark">`.

To use the body id as a trigger, you can follow the example below to switch the text color corresponding to the current theme.

```less
// index.css
#light .text-color {
  color: "black";
}
#dark .text-color {
  color: "white";
}
```

## Theme Detector

For better development experience, the platform set up a [postcss](https://postcss.org/) process for auto-detection and prepending the correct selector (i.e. either #light or #dark). To activate this feature, you only need to define your styles by less file and rename it to either `[filename].light.less` or `[filename].dark.less`; We also accept `light.less` or `dark.less` for short. The process will detect its extension and prepend the prefix to all styling within the file.

```less
// light.less

// Before
.text-color {
  color: "black";
}
// After
#light .text-color {
  color: "black";
}
```

```less
// dark.less

// Before
.text-color {
  color: "white";
}
// After
#dark .text-color {
  color: "white";
}
```


# Customizing Styles

#### :thumbsup: Following the default design

If you're not sure how to build customs for your DApps, we highly recommend that you should follow the default design, which is a variant of Ant Design. By using the default, you have no worries about style matching and theme (light/dark).

## Using Ant Design

Because the platform is currently using Ant Design for UI implementation, another customized Ant Design in DApps must follow some additional steps to make sure both Ant Designs can work separately.

1. Wrap your Page and Widget in UIProvider with active `antd` property.
2. All the styles must be written by `less` files.
3. Optionally support light/dark theme. See [Theme](/advanced-usage/theme).

#### Examples

```tsx
// bootstrap.app.tsx
<UIProvider appId={appId} antd>
  <Page/> // Or <Widget/>
</UIProvider>
```

```less
// light.less
.text-color {
  color: "black";
}

// dark.less
.text-color {
  color: "white";
}
```

To isolate your styling, the platform employed CSS Selector to scope the DApp's styling. Basically, there is a wrapper with id being your appId. All styles in your DApps will be prepended by a `#[appId]` selector.

```tsx
// Before
const appId = 'my_app'
<UIProvider appId={appId} antd={{ prefixCls: appId }}>
  <p className="text-color">A text with scoped styling</p>
</UIProvider>

// After
<section id="my_app">
  <p class="text-color">A text with scoped styling</p>
</section>
```

```less
// Before
.text-color {
  color: "cyan";
}

// After
#my_app .text-color {
  color: "cyan"
}
```

## Using other UI systems

In this time, you can freely use your favorite UI systems to build DApps. However, be careful that there may exist other DApps that use the same UI system as your DApps, but with customized styles, and that case will lead to styles conflicts. Then if your UI system supported scoped css, css modules, or any techniques that help to isolate customized styles, let's apply it in the first place to avoid possible problems.


# Hooks

Hook utilities for conveniently combining the essential data in functional components.

### useMintDecimals

**Prerequisites:** [MintProvider](/development/providers/mint-provider)

**Params:** [mintAddress](https://github.com/DescartesNetwork/senhub/blob/master/src/shared/hooks/useMintDecimals.ts)

```tsx
import useMintDecimals from 'shared/hooks/useMintDecimals'

const Component = () => {
    const decimals = useMintDecimals('SENBBKVCM7homnf5RX9zqpf1GFe935hnbU4uVzY1Y6M')
}
```

### useMintSupply

**Prerequisites:** [MintProvider](/development/providers/mint-provider)

**Params:** [mintAddress](https://github.com/DescartesNetwork/senhub/blob/master/src/shared/hooks/useMintDecimals.ts)

```tsx
import useMintSupply from 'shared/hooks/useMintSupply'

const Component = () => {
    const supply = useMintSupply('SENBBKVCM7homnf5RX9zqpf1GFe935hnbU4uVzY1Y6M')
}
```

### useAccountBalance

**Prerequisites:** [WalletProvider](/development/providers/wallet-provider), [MintProvider](/development/providers/mint-provider), and [AccountProvider](/development/providers/account-provider).

**Params:** [accountAddress](https://github.com/DescartesNetwork/senhub/blob/master/src/shared/hooks/useAccountBalance.ts)

```tsx
import useAccountBalance from 'shared/hooks/useAccountBalance'

const Component = () => {
    const {
        amount, // <bigint> balance with decimals
        balance, // <number> balance without decimals
        decimals, // <number> mint decimals
        mintAddress, // <string> mint address
    } = useAccountBalance('H2yPHiZm2U53GN93iUhQAwMwkjKHRSN7BGZpLLHv7d1m')
}
```

### useAccountBalanceByMintAddress

**Prerequisites:** [WalletProvider](/development/providers/wallet-provider), [MintProvider](/development/providers/mint-provider), and [AccountProvider](/development/providers/account-provider).

**Params:** [mintAddress](https://github.com/DescartesNetwork/senhub/blob/master/src/shared/hooks/useAccountBalance.ts)

```tsx
import { useAccountBalanceByMintAddress } from 'shared/hooks/useAccountBalance'

const Component = () => {
    const {
        amount, // <bigint> balance with decimals
        balance, // <number> balance without decimals
        decimals, // <number> mint decimals
        mintAddress, // <string> mint address
    } = useAccountBalanceByMintAddress('SENBBKVCM7homnf5RX9zqpf1GFe935hnbU4uVzY1Y6M')
}
```


# Submitting DApps

Apply your DApps to Sen Store

#### Prerequisite

```
// Build a manifest
npx create-senhub-app manifest
```

You need to run `npx create-senhub-app manifest` to create a manifest file of your DApp first. This file will contain all the needed information for your submission.

```json
// my_app.manifest.json
{
  "url": "https://tuphan-dn.github.io/my-app/index.js",
  "appId": "my_app",
  "name": "My App",
  "author": {
    "name": "Tu Phan",
    "email": "tuphan@descartes.netowkr"
  },
  "tags": [
    "solana",
    "dapps"
  ],
  "description": "A sample project for Sentre developers",
  "verified": false
}
```

#### Publish the repo

To publish the repo (your DApps hosting), you have to change and save the **Source** to the `gh-pages` branch.

![Github Pages](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FAlZ0hJSbfALVYT1u5BLj%2F1.png?alt=media\&token=cdd2ba68-a341-4ac8-8106-651a57f9c6aa)

#### Submission

1. Fork <https://github.com/DescartesNetwork/senreg>
2. Add your manifest file (e.g. `my_app.manifest.json`) to `src`.
3. Create a pull request to <https://github.com/DescartesNetwork/senreg> for submission.


# References

Essential dependencies in Sentre

| Name                 | Description                                             | Homepage                                                                        |
| -------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Ant Design           | The foundation that Sentre UI/UX relies on              | <https://ant.design/components/overview/>                                       |
| React                | A JavaScript library for building user interfaces       | <https://reactjs.org/>                                                          |
| Redux Toolkit        | A Predictable State Container for JS Apps               | <https://redux-toolkit.js.org/>                                                 |
| SenJS                | A Typescript library for Sentre.                        | <https://descartesnetwork.github.io/sen-js/>                                    |
| Solana Web3          | The foundation that SenJS relies on                     | <https://solana-labs.github.io/solana-web3.js/>                                 |
| Token List           | Metadata repo for tokens existing on Solana             | <https://github.com/solana-labs/token-list>                                     |
| Coin98 Integration   | Documentation for Coin98 Wallet Extension Integration   | <https://docs.coin98.com/products/developer-guide/solana-dapps-integration>     |
| Phantom Integration  | Documentation for Phantom Wallet Extension Integration  | <https://docs.phantom.app/>                                                     |
| Solflare Integration | Documentation for Solflare Wallet Extension Integration | <https://docs.solflare.com/technical/connecting-your-solana-dapp-with-solflare> |


# Best Practices


# Troubleshoots

### ERR\_OSSL\_EVP\_UNSUPPORTED

#### Problem

New Open SSL is not compatible with the legacy. This issue used to occur on NodeJS versions greater than 14.

```
Error: error:0308010C:digital envelope routines::unsupported
```

#### Resolve

Change the start command to:

```
craco --openssl-legacy-provider start
```

### NODE\_ENV is not recognized

**Problem**

The NODE\_ENV is not available for Node on Window.

```
'NODE_ENV' is not recognized as an internal or external command, operable program or batch file.
```

**Resolve**

Install `win-node-env` by the command:

```
npm install -g win-node-env
```


# Design Pricinples


# Button

Buttons allow users to take actions, and make choices, with a single tap.

### Usage

A button means an operation (or a series of operations). Clicking a button will trigger corresponding business logic.

In SenOS we provide 3 types of button:&#x20;

* Primary button: indicate the main action, one primary button at most in one section.&#x20;
* Default button: indicate a series of actions without.&#x20;
* Text button: used for the most secondary action.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FtumgFSQAZUJF2akkqmHt%2FButton%201.png?alt=media\&token=e13b74de-86e0-44c9-8ea1-d8adc605c561)

And 3 states:&#x20;

* Hover: used for the action of putting the mouse pointer on the button.&#x20;
* Pressed: used for button click action.&#x20;
* Disabled: when actions are not available.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Ff1r0o9kbllAeMhMx1Cea%2FButton%202.png?alt=media\&token=14221dcc-f4c6-442c-a376-b490bf5063cd)

### Specs

We provide 3 sizes of button:&#x20;

* Large

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FreJR6mZUwg1WAdMR3tH3%2FButton%203.png?alt=media\&token=ff6e4537-718d-4347-9f83-046db834368d)

* Default

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FgLQOASgp7BbBeGW55fzN%2FButton%204.png?alt=media\&token=b800f7dd-9748-42e1-9a62-a6f89fa326a9)

* Small

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FQkHG45ZRZIzVoOYd98fj%2FButton%205.png?alt=media\&token=907d465a-dba9-461f-a50f-477d13a175b3)

### Sample code

```
// Some code
```


# Card

A card can be used to display content related to a single subject. The content can consist of multiple elements of varying types and sizes.

### Usage

Cards are surfaces that display content and actions on a single topic. They should be easy to scan for relevant and actionable information. Elements, like text and images, should be placed on them in a way that clearly indicates hierarchy.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FriI5YsG1EIy6PlW1vIip%2FCard%201.png?alt=media\&token=d6eb27f7-c88c-41e7-90d6-1c196c98270a)

### Guidelines

Sen OS uses max two levels of the card depending on inside contents.

They have the same color and use elevation to distinguish each other. The default elevation value we use for two levels of the card is 4px.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FHPwmvY4xcDpR2H1MlORA%2FCard%202.png?alt=media\&token=02e14479-2a8a-4342-bd38-e10e93495670)

Some system elements will be set as level 1 card:&#x20;

* Modal&#x20;
* Drawer&#x20;
* Popconfirm

### Examples

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FzXhOnvJLSTKwbEpYPRL3%2FCard%203.png?alt=media\&token=145ea188-6d11-4720-9f35-233dccff113d)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fghrwu1gDIwFobiEAhtdZ%2FCard%204.png?alt=media\&token=a76ed0ab-ff71-4770-a1d4-b7b39be5a9c5)

### Sample code

```
// Some code
```


# Checkbox

Checkbox component.

### Usage

* Used for selecting multiple values from several options.
* If you use only one checkbox, it is the same as using Switch to toggle between two states. The difference is that Switch will trigger the state change directly, but Checkbox just marks the state as changed and this needs to be submitted.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FY7HnaQzrzH2WbqJ6UWe2%2FCheckbox%201.png?alt=media\&token=ae7bf5b7-0cf4-420f-a037-c55c569f9ed7)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FnvWr2tgFuXo8xohpTtd6%2FCheckbox%202.png?alt=media\&token=39ed5cdc-bf8e-4368-a805-fa69c59d55cc)

### Sample code

```
// Some code
```


# Color

Color provides an intuitive way of communicating information to users in your app: it can be used to indicate interactivity, give feedback to user actions, and give your interface a sense of visual co

### Color principles

**Use color meaningfully:** When color is used sparingly to highlight important elements, it can help create a user interface that is fluid and intuitive.

**Use color to indicate interactivity:** It's a good idea to choose one color to indicate elements of your application that are interactive. For example, many web pages use blue text to denote a hyperlink.

### Color palettes

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fzjw9A60rwRBXz6BkEBsJ%2Fcolor%201.png?alt=media\&token=81e5c795-bc60-4903-8380-973af85b1c24)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Ft6IeT2M7UC28sPk3oQaM%2Fcolor%202.png?alt=media\&token=4c2df759-2ce4-4f67-a3a0-2c08a205aa90)

### Accent color

Common controls use an accent color to convey state information. By default, the accent color is the SystemAccentColor: <mark style="color:red;">**#F9575E**</mark> that users select in their Settings. However, you can also customize your app's accent color to reflect your brand.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FmRhAnmjRsIVsTZr3wVCe%2FColor%203.png?alt=media\&token=8556f1b0-8ccb-49ac-bdff-869004d52a5a)

You can use the accent color palette for color theming in your app. Below is an example of how you can use the accent color palette on a button.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FaoNOToQVG1rHC8H9vNTz%2FColor%204.png?alt=media\&token=90404473-3b7c-4a49-a507-21ea8dfb3436)

### Themes

SenOS's apps can use a light or dark application theme. The theme affects the colors of the app's background, text, icons, and common controls.

#### Light theme

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FP2mMN5zAd1Lxd8aymzYY%2FColor%205.png?alt=media\&token=b101ac0b-9123-4ba5-991e-8fc32008bf3d)

#### Dark theme

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FcoOXFiYFcJkVaAoXsbKE%2FColor%206.png?alt=media\&token=cfdf1671-86b7-41b4-b3ff-79c36a834540)

### Sample code

```
<Grid>
    <Grid.Resources>
        <CornerRadius x:Key="ControlCornerRadius">8</CornerRadius>
    </Grid.Resources>
    <Button Content="Button"/>
</Grid>
```


# Corner radius

Sen OS applies rounded corners to almost UI elements. The same applies to most common controls such as Button, Card, Input...

### Rounded corners

There are three areas of the controls where the rounded corner styles are used: large, medium and small dimension UI elements.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F7SxQ1YxsJab85QxteuN8%2FCorner%201.png?alt=media\&token=79f78f2d-ab7f-47ab-a537-91dec9667c1e)

#### 1. Large dimension UI elements

The default radius value we use for these UI elements is 16px.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FOGR3BKZlJzTsGy5DGxOa%2FCorner%202.png?alt=media\&token=f2de997d-df41-4183-bcb2-6671866fd296)

Sen OS uses max two levels of rounding depending on inside contents.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FrXblcCYjmfKE9lnIchL7%2Fcorner%203.png?alt=media\&token=a873d67a-10be-448e-a214-3fa670e12be7)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fx03mVSq79g479ZfWYWcA%2Fcorner%204.png?alt=media\&token=2337e40c-af70-4323-8ee3-a17e40019511)

**UI elements:**&#x20;

* Card&#x20;
* Modal
* Popconfirm

#### 2. Medium dimension UI elements

The default radius value we use for these UI elements is 8px.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FZoBc6PoLP5BwULRXCtDv%2FCorner%205.png?alt=media\&token=6a1fb97d-7749-42e5-a58e-5289b580f82d)

**UI elements:**&#x20;

* Button&#x20;
* Input&#x20;
* Select&#x20;
* Tooltip&#x20;
* List&#x20;
* Radio button&#x20;
* Dropdown

#### 3. Small dimension UI elements

The default radius value we use for these UI elements is 4px.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FTwjv8390yji3bdnSbGQy%2FCorner%206.png?alt=media\&token=ffd7797f-51d8-459e-9bd0-f4dc6737a346)

**UI elements:**&#x20;

* ScrollBar&#x20;
* Slider&#x20;
* Checkbox

### When not to round?

There are instances where the corner of a control should not be rounded, and we don't round these by default:

* Dropdown

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FqhTeFJb77Cnn6HtCpvW7%2FCorner%207.png?alt=media\&token=0bc2f600-fdbd-4b49-a9a3-9176b57b245a)

### Sample code

```
// Some code
```


# Drawer

A panel which slides in from the edge of the screen.

### Usage

A Drawer is a panel that is typically overlaid on top of a page and slides in from the side. It contains a set of information or actions. Since the user can interact with the Drawer without leaving the current page, tasks can be achieved more efficiently within the same context.

* Use a Form to create or edit a set of information.
* Processing subtasks. When subtasks are too heavy for a Popover and we still want to keep the subtasks in the context of the main task, a Drawer comes very handy.
* When the same Form is needed in multiple places.

### Examples

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FmuXHuDhpoPluFt5SPQc0%2FDrawer%201.png?alt=media\&token=0d8fa7fb-5c83-49c1-a941-dff29eaec948)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F1kHMLhwc1bdQ6M2wzV4c%2FDrawer%202.png?alt=media\&token=3d85453c-80ac-4c52-ac24-2debfe3af7af)

### Sample code

```
// Some code
```


# Dropdown

A dropdown list.

### Usage

When there are more than a few options to choose from, you can wrap them in a **Dropdown**. By hovering or clicking on the trigger, a dropdown menu will appear, which allows you to choose an option and execute the relevant action.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fq742TfZPptaqpUTBXq3b%2FDrop%201.png?alt=media\&token=8ad0ea92-ae9c-4408-a7a5-00dade63fdea)

### Specs

Dropdown with icon

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FAKf74GpxG5sz8WdweAAo%2FDrop%202.png?alt=media\&token=01b5ac6e-e883-4c0c-b6da-77c35f936871)

Dropdown with button

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FG0O1Vin8v3Hxr1gOugGj%2FDrop%203.png?alt=media\&token=7b790ee1-e109-4bf2-9d7c-69deed630b2f)

### Sample code

```
// Some code
```


# Grid

SenOS’s responsive layout grid adapts to screen size and orientation, ensuring consistency across layouts.

### Screen sizes & breakpoints

Apps can run on any device, which includes phones, tablets, desktops. With a huge number of device targets and screen sizes, rather than optimizing your UI for each device, we recommended designing for breakpoints:&#x20;

* XS (screen < 576px)&#x20;
* SM (576px <= screen < 768px )&#x20;
* MD (768px <= screen < 992px )&#x20;
* LG (992px <= screen < 1200px )&#x20;
* XL (screen >= 1200px)

### Widget dashboard

#### 1. Columns

Content is placed in the areas of the screen that contain columns.

* At breakpoints of XL and LG, this layout grid uses 4 columns.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FIwzFvMrITZRX9d5MQGlw%2FGrid%201.png?alt=media\&token=96782f98-7019-4a28-9994-2c2f07c33ad0)

* At breakpoints of MD and SM, this layout grid uses 2 columns.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FZaS1l6vO9Dmq2bk5xYqV%2FGrid%202.png?alt=media\&token=d04e09fb-c5e0-47ac-8617-76a66daeb81f)

* At a breakpoint of XS, this layout grid uses 1 column.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FiewyvvG8XhGkMgChCTTE%2FGird%203.png?alt=media\&token=87876d88-c184-49e3-8d63-38618c64c03f)

#### 2. Widget size

Sen OS uses three levels of widget size: large, medium, and small. Corresponding to each breakpoint will use a different number of columns.

* The large size of the widget

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F6O7gNjdAVLRozgIiDdjZ%2FGrid%204.png?alt=media\&token=13e8035f-2ce8-4817-bee7-e9e3bf0721a3)

* The medium size of the widget

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FoRr5u0XYGGRtZbbGAtpj%2FGrid%205.png?alt=media\&token=35660566-adc6-41f0-a123-7b15ae955839)

* The small size of widget

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FzFGHvnAKbkrMauVDwB7l%2FGrid%206.png?alt=media\&token=9eeb62cb-84a8-4036-9c2f-7e4b99786b57)

#### 3. Gutter

A gutter is a gap between columns by horizontal and components by vertical that helps separate content.

At a breakpoint of XL, LG, MD, and SM, this layout grid uses 24px gutters for both vertical and horizontal. The XS doesn’t have a horizontal gutter but still uses 24px vertical gutters.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FX5BSP59cvhJIhnY2AEqA%2FGrid%207.png?alt=media\&token=34802b5a-eeeb-4e87-b5b6-c498f17952df)

#### 4. Margin

Margins are the space between content and the left and right edges of the screen. All breakpoints use 16px margins.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FTSZxjuKNIDrcAeQCA5AF%2FGird%208.png?alt=media\&token=40c6a07f-f88f-4fae-8c77-337fe7db26c4)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FM2WnkBVEv5PBqFl4s6NW%2FGrid%209.png?alt=media\&token=d764c646-8ee5-413f-93b1-0a64206a17f0)

### Application detail

This layout grid uses 24 columns for every breakpoint.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FAP2ZYtm3uZWRrWUzl6f7%2FGrid%2010.png?alt=media\&token=16906020-dd1c-4591-82aa-003674d67c12)

We set the value of the Gutter of the grid in the page, such that when the browser expands or shrinks in a certain range, the column width of the grid will expand or shrink accordingly, but the width of the gutter is always fixed.

### Sample code

```
// Some code
```


# Icons

Iconography is a collection of visual images and symbols that help users understand and navigate your app. Icons are used throughout the user interface as visual metaphors that represent a concept, ac

### Application icons

Application icons represent your app in the SenOS. They are primarily used to launch your application, but also represent your app wherever it appears in the SenOS:

* Navigation
* Dashboard
* Widget info
* Control center

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FHljg3LRbjQ7GZrQdPS1I%2FIcon%201.png?alt=media\&token=99c4c9ff-439d-4445-a338-710f284108d6)

### System icons

By default, the icon uses the ionicons library.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FLL7xRjELQ0IIX7Q8T4b0%2FIcon%202.png?alt=media\&token=52cd8ad9-ce54-48b7-b6f0-9d3f213638d0)

#### 1. When to use icons?

Use an icon for actions, like cut, copy, paste, and save, or for navigation items in a navigation menu.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FQzaNWLW1olMXct1zTupn%2FIcon%203.png?alt=media\&token=261bbe45-f176-498b-bf8e-de220de6d6c0)

Use an icon if it's easy for the user to understand what the icon means and it's simple enough to be clear at small sizes.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F0mLe9dsDQJDecUESeovI%2FIcon%204.png?alt=media\&token=ca0a1596-cee1-4cf2-92df-26c1cc07a133)

#### 2. Use a Scalable Vector Graphics (SVG) file

SVG resources are ideal for icons, because they always look sharp at any size or resolution. You can also use a bitmap image, such as PNG, GIF, or JPEG, although we don't recommend it. When the image is scaled down (shrunk), it can appear blurry; when it's scaled up, it can appear blocky and pixelated.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FGRgzKkZoT0rrm08F6fuV%2FIcon%205.png?alt=media\&token=b5e9daca-5e86-490a-8d34-b1ccd27a30a2)

#### 3. Corners

Consistent rounding of corners and sizing of angles is also an important element in maintaining visual unity.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FC6NyNHaZeYIltRLdiZVY%2FIcon%206.png?alt=media\&token=d82851ab-4d01-4193-b164-7060f69eb3a6)

#### 4. Outline icons

Icons should be used synchronously and consistently in one type. We use default in outline format.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FzE9cHynVhLHm3PQAaZk1%2FIcon%207.png?alt=media\&token=1deacc18-8ebf-4278-ab02-0d944b3565be)


# Input

A basic widget for getting the user input is a text field. Keyboard and mouse can be used for providing or changing data.

### Usage

* A user input in a form field is needed.&#x20;
* A search input is required.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FAbeYsMFE9Fa3l56HmivB%2FInput%201.png?alt=media\&token=7aa91416-6a93-43a3-ba38-2d79d081e47e)

### Specs

We provide 3 sizes of input: large, default and small.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F4Yb07JGLHjOyEwVWE32l%2FInput%202.png?alt=media\&token=62ab4865-3700-4176-afc1-332b2746cfae)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FATnoL1LBwWxAwFYazwUu%2FInput%203.png?alt=media\&token=bb16511d-4398-4105-9bd4-03c6c6de8a85)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fjh2DhQa8j84dDqWSWgtB%2FInput%204.png?alt=media\&token=8e001da9-f82d-4a31-a70f-cbb06807c1a2)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FdLvaNZiIZnw44lAnrH7G%2FInput%205.png?alt=media\&token=6ca3e789-e8ec-4123-8d82-b09861f1c22e)

### Sample code

```
// Some code
```


# List

Lists are continuous, vertical indexes of text or images.

### Usage

A list can be used to display content related to a single subject. The content can consist of multiple elements of varying type and size.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FCaVnMto2X6d70vAsOz0Y%2FList%201.png?alt=media\&token=d11a7831-d3b2-4a3a-a1ff-22968f78752e)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FYTM2y8N8aNWlMZZAOHRa%2FList%202.png?alt=media\&token=f7dd3246-0bbc-457a-bb28-d916bc2a6b7d)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FmNzHdWgh8bQFPvwIcjvT%2FList%203.png?alt=media\&token=4b17c8ed-88cc-4b38-becd-57f4a3009b13)

### Sample code

```
// Some code
```


# Menu

While there's no single navigation design that works for every app, there are principles and guidelines to help you decide the right design for your app.

### Principles of good navigation

Let's start with the basic principles of good navigation design:

#### 1. Simplicity

Fewer navigation items simplify decision making for users. Providing easy access to important destinations and hiding less important items will help users get where they want, faster.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FyhKwDMvGl5Vlcm48C7hd%2FMenu%201.png?alt=media\&token=10be27c2-ca64-4bb1-90dd-1c8a1580bfe3)

#### 2. Clarity

Clear paths allow for logical navigation for users. Making navigation options obvious and clarifying relationships between pages should prevent users from getting lost.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F5UxBPzOyVycgyCU4ylUP%2FMenu%202.png?alt=media\&token=5a1c1b90-3f6c-4176-ad87-62d3d918ca01)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FBoPrbWtxO0Grv4xh7ywL%2FMenu%203.png?alt=media\&token=1cbb5f79-4bcf-4785-8fab-1f66096c380c)


# Modal

Modals inform users about a task and can contain critical information, require decisions, or involve multiple tasks.

### Usage

When requiring users to interact with the application, but without jumping to a new page and interrupting the user's workflow, you can use Modal to create a new floating layer over the current page to get user feedback or display information.

### Examples

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FnhvEvwWXYPiRmGVPlw1T%2FModal%201.png?alt=media\&token=28d6550b-9fe7-46b4-9019-a5d544b5b94f)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FA9ZkzB5lzu0Wl9uckkC0%2FModal%202.png?alt=media\&token=a5706155-4e4c-489a-9171-70380df7dfc4)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FrLy8tQEsDaiVGkqlEeGb%2FModal%203.png?alt=media\&token=937dc0f8-eaf9-4aa2-97b4-42db5713f7c8)

### Sample code

```
// Some code
```


# Radio

Radio component.

### Usage

* Used to select a single state from multiple options.
* The difference from Select is that Radio is visible to the user and can facilitate the comparison of choice, which means there shouldn't be too many of them.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FHpfFB10jlGSpGCyWqMi0%2FRadio%201.png?alt=media\&token=94df107a-427a-4cd5-bffd-a0290d39d450)

### Specs

#### 1. Basic

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FpBo7U12kUN3mb18uhkjf%2FRadio%202.png?alt=media\&token=ba40fb35-75f3-4fb8-9795-74c38f704706)

#### 2. Radio button

We provide 3 sizes of radio button: large, default and small:

* Large

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FeDM4sM896PvQeWNRPasu%2FRadio%203.png?alt=media\&token=ff572b67-7265-413f-af1f-86e43bfa35b6)

* Default

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FwrlEsNCQ5AiF1AOxvv0d%2FRadio%204.png?alt=media\&token=4f99a7da-41c4-4608-8fa9-352ab845df07)

* Small

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FjWUBR9DMUfNR3phqsgT0%2FRadio%205.png?alt=media\&token=ed1d32ba-374f-4a12-868f-ba52e4780f7a)

### Sample code

```
// Some code
```


# Select

Select component to select value from options.

### Usage

A dropdown menu for displaying choices - an elegant alternative to the native element. Utilizing Radio is recommended when there are fewer total options (less than 5).

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FVbOwOSXrwWCLCXonjyWo%2FSelect%201.png?alt=media\&token=97c99d0b-46e2-4910-bcb9-ad901bcc76b1)

### Specs

We provide 3 sizes of select: large, default and small:

* Large

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F4s5rWpftEQMMRXkxwkyw%2FSelect%202.png?alt=media\&token=3c2cbbc3-6b4c-49d6-aac9-5bbcff7ee4f9)

* Default

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FFdgZ0v06Chxx8NdENc0y%2FSelect%203.png?alt=media\&token=e3617dca-5a95-4104-95f8-635cdd4a2238)

* Small

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FidOiO7xZRWWDvtDPfTW4%2FSelect%204.png?alt=media\&token=0e9fc49f-50d8-492e-9eb0-907f6641afc8)

### Sample code

```
// Some code
```


# Shadow

Shadows provide cues about depth, direction of movement, and surface edges. A surface’s shadow is determined by its elevation and relationship to other surfaces.

### Usage

Because shadows express the degree of elevation between surfaces, they must be used consistently throughout your product.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FjAUQCbHF7tdD8jkwWNx9%2FShadow%201.png?alt=media\&token=a99102ff-ce08-478c-9a95-5ca0576983d2)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FReVh8k4ZOXilFzRQ8P5N%2FShadow%202.png?alt=media\&token=2808a637-54ee-431d-b49d-6511a469d70f) ![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FtxAugYklMgHfMIZtlbLD%2FShadow%203.png?alt=media\&token=e58e807b-f809-48e2-a839-c1eef579a649)

### Soft shadow

The soft shadow creates a more natural and clean feel to the interface. The default **elevation** value we use is **4px**.

#### 1. Light theme

**The opacity (12 - 20%)** and **the higher level of blur (32 - 40px)** - This configuration builds a soft shadow for the light theme.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F7Xyg7Yks2WQRJMDiLGrE%2FShadow%204.png?alt=media\&token=3f01b152-e818-431f-a044-1c33329265dc)

#### 2. Dark theme

**The opacity (32 - 40%)** and **the higher level of blur (32 - 44px)** - This configuration builds a soft shadow for the dark theme.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FAH1f7VtJncpXW0UidbAh%2FShadow%205.png?alt=media\&token=f1c058d3-2547-4c47-81f0-84fadabb9dab)

### Sample code

```
// Some code
```


# Spacing

Use a combination of control size and density to optimize your application and provide a user experience that is most appropriate for your app's functionality and interaction requirements.

### 4px rule

#### 1. Spacing methods

We have a common set of spacing, and all the numbers are multiples of 4. Spacing should be used in accordance with the content to create a reasonable space.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FVb9CbOo78GZlTfnpu0Tb%2FSpace%201.png?alt=media\&token=1a4db2ee-c7a6-4d83-b4d5-57f870466741)

#### 2. Dimensions

Dimensions refer to the width and height of component elements.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FtLs1Ot9zCdWAMFM7Aukp%2FSpace%202.png?alt=media\&token=64f20c1a-1be2-42fa-a003-f450cd767d04)

### Examples

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FvOIFecReIHk9gotphmad%2FSpace%203.png?alt=media\&token=85fdb01b-7ec2-4548-a418-fa05032df0e0)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FAIwgIEzqGoC2OHXHOUj5%2FSpace%204.png?alt=media\&token=18ed9fd9-3264-41dd-be22-ceb7931cc3de)

### Sample code

```
// Some code
```


# Switch

Switching selector.

### Usage

* If you need to represent the switching between two states or on-off state.
* The difference between Switch and Checkbox is that Switch will trigger a state change directly when you toggle it, while Checkbox is generally used for state marking, which should work in conjunction with submit operation.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FABhh9githN0Z8zsSU11O%2FSw%201.png?alt=media\&token=3769a589-4010-4e5c-84c1-c9825cd3b0f2)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FwiCB1TKGaThD1f8JAfmM%2FSw%202.png?alt=media\&token=a73367ad-12c9-4e5b-88f5-dd93840605ca)

### Sample code

```
// Some code
```


# Tabs

Tabs make it easy to switch between different views.

### Usage

Tabs organize and allow navigation between groups of content that are related and at the same level of hierarchy.

### States

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F9Vsh35FoYwjLLOxanKFH%2FTab%201.png?alt=media\&token=b06ba4bd-dbc1-41c5-8129-48f170f80290)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fhy1JVPRnEqL1dWL8rKZv%2FTab%202.png?alt=media\&token=6669bf8a-2bb6-49ff-94b2-4306f8ff19b5)

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fy58ESuVOXP4E6ZErduif%2FTab%203.png?alt=media\&token=8db076d1-995f-459b-9527-b89659d5f36d)

### Sample code

```
// Some code
```


# Tooltip

A simple text popup tip.

### Usage

Tooltips display informative text when users hover over, focus on, or tap an element.

### Examples

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FDX08SRAfvQlkvG9gFqPM%2FTooltip%201.png?alt=media\&token=3bd4d6fe-5287-4a4d-9277-48fac0bab184)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FMj1nIFRPxIz2yfLdjgyi%2FTooltip%202.png?alt=media\&token=3488bd33-7282-4068-b217-6cf987e0124a)

### Sample code

```
// Some code
```


# Table

A table displays rows of data.

### Usage

* To display a collection of structured data.
* To sort, search, paginate, filter data.

### Examples

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fb1ZENfYyVWmtYiLDQLJB%2FTable%201.png?alt=media\&token=06b2997d-81ff-4b48-ac1e-fd5419007b00)

### Specs

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FLxTqTxG69IWRQZDBDH0C%2FTable%202.png?alt=media\&token=32bc94dd-6100-48f4-a2bb-16bceb9c0cc2)

### Sample code

```
// Some code
```


# Typography

Basic text writing, including headings, body text, lists, and more.

You should use one font throughout your app's UI, and we recommend sticking with the default font of the platform - **Nunito**.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FoAboXmrvejczk78x1iXT%2FTypo%201.png?alt=media\&token=89ce6383-4684-4b5c-a6f6-7a9278fd1877)

### Guidelines

Our recommended base font size is **14px** and its corresponding line-height is **22px** for both desktop and mobile interfaces

#### 1. Desktop & tablet

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F4IzUFlGMxkHK5SreN0WT%2FTypo%202.png?alt=media\&token=8bb653bc-afe9-43b6-bccc-69c80e42f0f6)

#### 2. Mobile

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FTa9ncwFJDVzxtICk15Vq%2FTypo%203.png?alt=media\&token=24fdcefe-b695-4142-ab4d-3023e61e53e5)

### Color

Text will be difficult to read if it is too close to the background color.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FjIqBcqZnoLjCcG37jNvE%2FTypo%204.png?alt=media\&token=6a50f67d-590a-44aa-bb9e-b9b1948f62f1)

### Examples

Users rely on visual hierarchy when scanning a page: headers summarize content, and body text provides more detail.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fws9Rqsc2z5FdQwmKw7rI%2FTypo%205.png?alt=media\&token=424af442-23d4-4415-90ee-fc5c0f637eca)


# Litepaper

Sentre: An Open Liquidity Protocol on Solana

*Abstract—In the early era of Decentralized Finance (DeFi), numerous decentralization apps (DApps) emerged and attracted huge liquidity from the community. The environment of DeFi, however, was quite chaotic since these DApps are built separately from each other with poor interfaces and limited connectivity to other services. Sen Team developed Sentre to tackle this problem, by gathering liquidity from multiple sources and creating an open space to give back to the community.*

*In this paper, we will introduce our all-in-one solution: An operating system (OS) specifically designed for DApps, fueled with efficient liquidity from an automated market-maker (AMM) allowing both dual and triad token pools.*

*Through Sen OS, developers can realize and integrate their ideas into Sentre’s ecosystem. The main source of liquidity for Sentre comes from SenSwap, by allowing users to either swap, stake or pool in dual-token or triad-token pools with the native utility token SEN in the middle. This protocol removes several technical barriers and reduces most of the exchange fee. DAO might be utilized as a democratic regime to make sure the liquidity can leverage innovative projects and grow the ecosystem.*

*Eventually, Sentre’s ecosystem will be run by the community.*

*Index Terms—blockchain, decentralized finance, open liquidity protocol, automated market making.*

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FUmMh8jRManzkELqu9afc%2FCover%20Twitter.png?alt=media\&token=552bfcec-6f8e-4b72-82ce-3a95758c4626)


# Introduction

Whitepaper - Rev. 02 by Sentre Protocol (hi\@sentre.io)

The idea of using Automated Market Maker (AMM) to build a decentralized exchange (DEX) was proposed for the first time in 2016. Two years later, the earliest form of the idea, named Uniswap, was launched in November 2018. However, traffic on Uniswap was quite low for the first three years. Its liquidity finally reached one billion US Dollars for the first time in August 2020. Nowadays, Uniswap has become a key component of the Decentralized Finance (DeFi) market that leverages numerous DeFi applications and builds up a robust DeFi ecosystem.

Uniswap is just one of the many examples of a great idea being ignored for so long before someone discovers it and gives it a chance. We believe many great and benefiting ideas are still out there, struggling to find financial and technical support to grow.

Only a small number of projects have recognized that limitation and tried to get around it by building a comprehensive ecosystem with multiple existing services on the market. However, those projects are reserved and liquidity is not open to the public.

Contrary to that, Sentre believes that openness is the key to DeFi development as a whole, as well as the Sentre ecosystem in particular. To do that, **Sentre provides developers with a well designed tool-chain to accelerate the DApp building process right from the start**. If those DApps can prove to create meaningful impacts for users, they will be allowed to inherit available liquidity accumulated from the community.

To bring this ecosystem into action, Sen Team created an open platform for DApps developers and users called Sen OS. This operating system aims to help developers find useful resources and available liquidity to build actual synchronized DApps, while offering users verified, high ROI yielding DApps. By doing this, **Sen OS helps erase the inconsistency in DApp quality and interface, and keeps the ecosystem’s environment open but safe for users**.

Liquidity is an essential part for this plan to work out. To implement our vision of an open protocol, Sen Team chose to carefully craft an AMM service as the universal interface, integratable with other services to expand the ecosystem.

![Sentre Ecosystem is built to accommodate both Users and Developers in DeFi.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FnVATIH6Gmq0XTZ4oy0ZJ%2FFlow%20WhitePaper%20Sentre.png?alt=media\&token=6eb996ee-af1f-44bf-b381-b9a3519eaa20)


# Industry Problems

Sentre decides to tackles the four main problems in the DeFi market.

## Liquidity Openness

In 2020, Uniswap introduced its version 2, which mentioned the concept of programmable liquidity. At one point, it is similar to the concept of an open liquidity. They opened and conducted a method to implement on-chain price oracles, which can be considered open data. Uniswap also utilizes the atomic property of Ethereum to leverage flash swaps. In short, you can ask for tokens before paying them with some conditions. If the conditions aren’t met, the transaction will be rolled back. The flash swaps are a superpower for arbitrageurs to explore the price differential.*<mark style="color:purple;">\[1]</mark>*

It’s clear that the liquidity openness on Uniswap is still limited when Liquidity Provider Token (LPT) cannot be consumed by other financial services. In the last half of 2020, the term “Yield Farming” was gathering notice as it accepted LPT to earn other tokens. However, these services are dependent on third parties without native support from Uniswap.*<mark style="color:purple;">\[2]</mark>*

SushiSwap is a younger but more innovative AMM than existing platforms before. It provides a comprehensive DeFi market with many services including swap, yield farming, lending & borrowing, staking, and so on. All these services are built up by themselves, which means they fully control the liquidity and circulate it in their platform. On Solana, Raydium is the current top DEX. Currently, they have services such as swapping, staking, and farming. However, Raydium seems to share the same vision as SushiSwap when they maintain the private permission in DeFi services development.*<mark style="color:purple;">\[3]</mark>*

## Symmetric Deposit

It’s worth mentioning about the constant product function (CPF) which expresses the pricing curve in the aforementioned protocols. The main idea behind seems very simple, but it has strongly proved functionality and possibility in both experimentall&#x79;*<mark style="color:purple;">\[4]</mark>* and practically. The CPF formulates the quoted price via the pair of token reserves. Giving token $$A$$, and $$B$$ with corresponding reserves $$R\_A$$, $$R\_B$$, the algorithm will maintain the following equation,

(1) $$R\_A\*R\_B=k$$

where $$k>0$$ is a constant defined at the initial stat&#x65;*<mark style="color:purple;">\[5]</mark>*. In other words, let’s call α$$α$$ the “changing rate” of $$R\_A$$ after an exchange (sell $$A$$, buy $$B$$ for example). Then $$R'\_A=\frac{1}{α} R\_A$$ induces $$R'\_B = αR\_B$$, where $$0<α<1$$, to maintain the constant product,

(2) $$R\_A× R\_B = R'\_A×R'\_B= k$$

At an arbitrary timestamp $$t$$, the quoted price $$p^{(t)}=R^{(t)}\_B/R^{(t)}\_A$$. Therefore, the first liquidity provider (LP) must deposit both tokens, A and B, with reserves that satisfy the reference market price at the initial state, $$p^{(0)}=R^{(0)}\_B/R^{(0)}\_A$$. After the pool’s setup, subsequent LPs must follow the quoted price by depositing both tokens accordingly. But what if users only have one type of token? We call this problem **Symmetric Deposit**.

## Swap Possibilities

***Definition 1.** Let* $$p$$ *be the current quoted price,* $$p'$$ *be the next quoted price, then a slippage rate,*

(3) $$s=\frac{p'}{p}$$.

Applying to the CPF,

(4) $$s=\frac{R'\_B/R'\_A}{R\_B/R\_A}=α^2.$$​

The slippage rate is amplified when routing. When there are no direct pools for the desired pair of tokens, traders need to swap through other middle tokens before reaching the destination, and even then, there might be no route for said desired pair at all. This problem, called Swap Possibilities, reduces the liquidity effectiveness and affects user experience.

## Impermanent Loss

Lastly, one of the biggest risks of liquidity provision is impermanent los&#x73;*<mark style="color:purple;">\[6]</mark>*. Due to price deviation or reserves deviation, from the initial state, the value of assets is no longer greater than or equal to a HODL strateg&#x79;*<mark style="color:purple;">\[7]</mark>*.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

*<mark style="color:purple;">\[1]</mark> H. Adams, N. Zinsmeister, and D. Robinson, “*[*Uniswap v2 core*](https://uniswap.org/whitepaper.pdf)*,” 2 2020. \[Online].*

*<mark style="color:purple;">\[2]</mark> K. Rapoza, “*[*DeFi ‘Yield Farming’: How To Get DeFi Yield, And Why Invest In It*](https://www.forbes.com/sites/kenrapoza/2021/06/06/defi-yield-farming-what-is-it-how-should-you-invest-in-it/?sh=5786f4052193)*,” 06 2021. \[Online].*

*<mark style="color:purple;">\[3]</mark> Raydium Team, “*[*Raydium Protocol Litepaper*](https://raydium.io/Raydium-Litepaper.pdf)*,” 03 2021. \[Online].*

*<mark style="color:purple;">\[4]</mark> G.Angeris, H.-T.Kao, R.Chiang, C.Noyes, and T.Chitra, “An Analysis of Uniswap Markets,” Cryptoeconomic Systems Journal, 2019.*

*<mark style="color:purple;">\[5]</mark> H. Adams, “*[*Uniswap Whitepaper*](https://hackmd.io/@HaydenAdams/HJ9jLsfTz?type=view)*,” 11 2018. \[Online].*

*<mark style="color:purple;">\[6]</mark> N. Hindman, “*[*Beginner’s Guide to (Getting Rekt by) Impermanent Loss*](https://blog.bancor.network/beginners-guide-to-getting-rekt-by-impermanent-loss-7c9510cb2f22)*,” 11 2020. \[Online].*

*<mark style="color:purple;">\[7]</mark> HODL: Hold On for Dear Life, a slang among the cryptocurrency community, meaning you should hold a cryptocurrency instead of selling it.*


# Sentre: An All-in-one Solution

Sentre aims to become the true Open and Safe Haven for both Users and Developers.

By allowing the native utility token named SEN to be enabled in all pools, the protocol introduces two models named **Simulated Single Exposure** and **Simulated Mesh Exchange**, which solve the problems of Symmetric Deposits and Swap Possibilities respectively. In practice, the AMM will automatically run these algorithms and provide transparency to users. Moreover, it also provides an instrument called the adaptive fee model that reduces the risk of impermanent loss.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FvlOqixPNjXrkMY49J3iN%2F12h-all-in-one%402x.png?alt=media\&token=0217e7a2-f4ef-4a77-84b3-e2dedfd01876)

For developers, Sentre will open up the chance to access available liquidity. We believe that it will encourage the number of public projects and the liquidity effectiveness.

Finally, Sentre’s products inherited outstanding properties from Solana. We make use of quick block confirmation time based on Proof-of-History on Solana and low fee for user attractio&#x6E;*<mark style="color:purple;">\[8]</mark>*.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

*<mark style="color:purple;">\[8]</mark> A. Yakovenko, “Solana: A new architecture for a high performance blockchain,” 2018.*


# The Open Protocol

Sentre is all about Openness.

## **Programmability vs. Openness**

Currently, most liquidity protocols are programmable, not open. Programmability means that some documents, software development kits (SDKs), or application programming interfaces (APIs) are provided to develop your applications on top of the protocol. However, they are by no means a native function on the protocol. A typical instance is Uniswap.

Uniswap allows developers to freely develop applications such as Staking services of LPTs, Oracles, Flash Swap services, and others. However, they’re certainly not available functions that you could find on the Uniswap application. These “sided” protocols live on many separate domains, making it difficult to manage all at once.

PancakeSwap, as well as SushiSwap, are both trying to serve as many wide-adopted services as possible on their platforms. Unfortunately, one solution can’t fit all. It’s clear that sometimes the platform is too inadequate or superfluous in functioning; or even both.

**Openness is different.** Applications from the community can be a native part on the Sentre platform. People can decide what they need and gather them together on one page. Sentre proposes a “DApp Store” concept where developers deliver their solutions to users who are free to pick and choose what suits them most.

The openness depicted above is still trivial compared to the openness in liquidity, though. All individuals involved in a pool can participate in deciding on liquidity usage. The exchange fee for LPs is compulsory and the LPTs depend on LPs’ favor, but the protocol charge seems more like a private reward for the foundation.

Sentre protocol being open means the protocol charge should encourage community projects, including projects developed by the foundation. At this moment, automation is really needed to realize the ability of plug-and-play, which allows a pool to effectively change the target of the charge. The problem solver here is SEN, the universal interface of Sentre’s ecosystem. SEN lets all charges be unified to a single interface. The community projects now only consume one socket, therefore, LPs are free from the complexity of multiple assets.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FkrQGbjiDmCz42Whb1KE8%2FBanner%20Day-10-Respect%402X.png?alt=media\&token=978095cd-e607-4167-ba2f-d4c945b15a2d)

## **Open Components**

These days, few liquidity protocols are occupying a large part of the global liquidity, while other projects are struggling to find sufficient liquidity. Open liquidity is an optimized way to circulate liquidity, increase effectiveness in liquidity usage, and encourage innovation from developers in the community.

### **Open Platform for DApps**

To increase the speed to realize ideas and deliver complete applications to users, developers must rely on many open-source frameworks and libraries. On top of that, newcomers must also put more effort into terminology understanding and technical stacks. This process could be shortened if there were full and detailed documents to support them.&#x20;

Therefore, we orientated the Sentre protocol towards being an Open Platform. Sentre will provide a complete solution with how-to documents for developers, newbies and seniors alike. As a basic stack (see **Fig. 1**), the tool-chain will include:

* A framework to develop smart contracts on Solana.
* A library to communicate between off-chain applications and smart contracts.
* A system UI to provide a consistent style for all applications.

![Fig. 1. The perspective of a full DApp is usually organized into three components. An application interface is to let users interact with the DApp. A smart contract is to run the main logic. And a library is to help the application interface call functions and read data from the smart contract. In usual cases, some backend servers are built to support the application interface. But these servers are optional so we can skip them in the general system.](https://lh4.googleusercontent.com/z7Hehad3L0ZKr6WUrFwXgpw8AN4rRQLFjQZELl5H36oKeqPD3Tb4InjV0bhnNVIvszCGC0AtJeEfUo2ZPEBRFNqRfjjjAqhtUbEyPIt7HmtTnbChTSVNXriL8WPGRCqTi1pn8LeY)

Developers can access the Sen Team’s github and browse through our repositories for materials and source codes, among other things. Sen Team also offers support and consulting services if needed.

### **Open Liquidity for Profitable Projects**

Putting the application development process aside, new projects also have to face the struggle of finding liquidity and users. By integrating themselves into Sentre’s ecosystem, they can inherit existing liquidity and the current set of users, which enables them to go faster and win earlier.

However, Openness doesn’t mean any and everyone can freely access and use the liquidity for their own purpose. In regard to liquidity access permission, the projects must prove their rational purpose and vision. Next, the SEN holder community will vote for their favorite projects. Winners will work directly with the Sen Team to correctly integrate their services into Sentre’s ecosystem. We are able to avoid scams or ineffective projects by these strict procedures. To realize this objective, DAO will be employed (see **Fig. 2**).

![Fig. 2. An application must be accepted by the Sentre community via voting before being integrated into the Sentre ecosystem by the Sentre foundation.](https://lh3.googleusercontent.com/naQJuBl3_3NVECtbmde9LN0hBZBkKKIBpOXrldiwJLHxxS_agRKirMOF0zOiO19qwW7DEbdA1pKuO1v6AUHIS8igNZmaTwK5eGpvNp4M34l8OjTm0Vxqwgq6cLF72V6oi_mjpDvv)


# Liquidity Efficiency

Not only an Open Platform, Sentre aims to provide a truly efficient flow of liquidity that benefits every Sentizens.

The liquidity flow of Sentre starts from SenSwap and Sen OS, then returns to developers and users in different ways.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FGrLnku8UJ2CtHB4RAlJA%2FBanner-Day-4-liquidity-21-10-2021%402x.png?alt=media\&token=82ae20eb-334b-43f4-b134-03b9ae8afe86)

## Liquidity from SenSwap

For SenSwap, activities like swapping, staking and pooling from LPs will be our traditional source of liquidity. SenSwap provides two options for liquidity providers to choose based on their preference:

### Main dual-token pools

Instead of limiting itself to stable coins or any specific ecosystem’s coins, SenSwap focuses on exotic, non-correlated pools. From these pools, SenSwap is able to accumulate and utilize cross-chain liquidity.

### Optional triad-token pools

For triad-token pools, SEN token will be the universal interface between any pair. With this, SenSwap is able to utilize liquidity from any and all pools, reduce confirmation time for users, perform price evaluation and liquidity automation, and so on.

It is entirely up to liquidity providers to choose between the two types of pools. To further aid such providers, Sentre also comes up with a Simulated Single Exposure model to enable Asymmetric Deposits (see [Asymmetric Deposit](/litepaper/sen-as-the-heart-of-the-ecosystem/asymmetric-deposit)).

## Liquidity from Sen OS

Aside from the traditional way through SenSwap, Sentre has another means to gather liquidity - that is through our Open Platform, Sen OS.

There are two types of dApps that are presented on Sen Store and work on Sen OS.

First are Solana-based dApps created and published by Sentre’s partners. These dApps will be integrated into Sen OS and appear on Sen Store. From this:

* Users can gather all their favorite dApps in one place and create a single-page workflow.
* Sentre’s partners can increase the amount of real, active users who love and frequently use their dApps.

Second are new, promising dApps created by developers - either as individuals or teams. By allowing them to access our resources and give support or consulting services when needed, Sentre creates a space where:

* Developers get to introduce their ideas to native and active users with real opinions and reviews.
* Users get to pick and choose from a variety of dApps, and put liquidity into the hands of the right projects.

From both types of dApps, Sentre accumulates liquidity generated and returns it to users through Yield Farming and other future features.

## Return to Developers and Users

After all, the purpose of our liquidity accumulator is to serve dApp developers and users and satisfy your needs for liquidity.

For developers, Sentre’s liquidity becomes inheritable when their idea or dApp gets chosen by the users. If their idea is truly useful to the community, they won’t have to worry about finding available liquidity. Instead, they only need to focus on making their dApps as awesome as possible!

For users, as a high liquidity environment, Sentre helps reduce confirmation time and lower fees and slippage rate. Also, as users deposit into Sentre’s pools, the LP tokens received can be staked to earn more rewards.

To encourage people to lock tokens, Sentre protocol needs to bootstrap and build momentum for liquidity from the start, and to do this, Sentre plans to utilize common strategies, namely **Farming** and **Auto Compound Farming**. Besides, wallet integration is also considered to create a native experience for users.

#### Farming

Roughly speaking, farming lets users stake their LPT to mint more SEN as rewards. Users will now become farmers, earning rewards as periodic and proportional as a farmer’s shares. There are three main functions for three main farming activities:

* Harvest: Collect rewards.
* Stake: Add LPT to a pool and receive a number of corresponding shares which is equal to the number of staked LPT.
* Unstake: burn shares and remove LPT from a pool.

At first look, Solana blockchain has an unusual approach to develop the “smart contract” concept and call it “program”. A program on Solana doesn’t have its own memory, storage, or anything to store states. Solana’s solution is extremely opposite to Ethereu&#x6D;*<mark style="color:purple;">\[9]</mark>*, which is the most adopted smart contract platform. As an interesting metaphor, we can think of Solana programs as punched-card computers, which are the very first versions of the digital computer in the 70s. Such computers need punched cards to provide inputs, algorithms, and even to write the outputs. Within the Solana programming concept, a punched card is represented by an account.

To adapt the novel model and secure user experience, DApps on Solana are required several special features including renting accounts, rent exemption, associated accounts, cross-program invocations, and many others.

Due to the limit of resources in the Solana programming model, farming cannot naively loop all accounts and update rewards in every period. Hence, we employ debt models to reduce the number of computations. For example, instead of updating the reward of each account periodically, the protocol shall update a single parameter named pool debt to describe how much the pool is owing to farmers.

***Proposition 2.** All farmer’s actions including harvest, stake, and unstake can be generalized by an order of fully harvest, fully unstake, fully stake where Fully Harvest: harvest all rewards to a personal account. Fully Unstake: unstake all LPT by returning all shares. Fully Stake: stake a specific LPT and receive a number of shares. Fully harvest is just the same as stake.*

Giving a pool created at timestamp $$t\_0$$with the periodic rewards $$p$$ and the number of farmers $$n$$, the $$i$$-th farmer's state is {$$𝔯\_i,δ\_i$$} where $$𝔯\_i$$ is the $$i$$-th farmer's shares and $$\delta\_i$$ is the farmer's debt $$(SEN)$$; And the pool's state is {$$𝔎,𝔇$$} where $$𝔎= \sum\_{i=0}^{n-1} 𝔯\_i$$ is the sum of shares and $$𝔇$$ is the pool debt $$(\frac{SEN}{Shares})$$. In the following equations, the pool has lived for $$t$$ periods and we use prime to represent for subsequent notations.

**Fully Harvest.** This action doesn’t change all shares. Then the $$i$$-th farmer will harvest $$s\_i$$ SEN,

(5) $$s\_i=𝔭t𝔯\_i-\delta\_i+𝔇𝔯\_i$$,

(6) $$\delta'\_i=\delta\_i+s\_i=(𝔭t+𝔇)𝔯\_i$$,

(7) $$𝔯'\_i=𝔯\_i,𝔎'=𝔎,𝔇'=𝔇$$.

**Fully Unstake.** This action must be after the Fully Harvest, and unstakes all $$𝔯\_i$$,

(8) $$𝔯'\_i=0,\delta'\_i=0,$$​

(9) $$𝔎'=𝔎-𝔯'\_i$$,

(10) $$𝔇'=𝔇+(𝔭-𝔭')t$$​

**Fully Stake.** This action must be after the Fully Unstake, and stakes $$𝔯\_i$$,

(11) $$𝔯'\_i=𝔯\_i$$,

(12) $$\delta'\_i=(𝔭't+𝔇')𝔯\_i$$,

(13) $$𝔎'=𝔎+𝔯\_i$$,

(14) $$𝔇'=𝔇+(𝔭-𝔭')t$$.

For example, you have staked and owned 1 share. You wish to stake 1 more token to own 2 shares. This desire can be generalized by a pattern:

1. Fully harvest.
2. Fully unstake 1 token.
3. Fully stake 2 tokens.

#### &#x20;Auto Compound Farming

Farming is not yet optimized when rewards can’t be re-invested to earn more profit. In the future, Sentre will tackle this problem by developing an automated process of compound interest for relevant tokens.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

*<mark style="color:purple;">\[9]</mark> G. Wood et al., “Ethereum: A secure decentralised generalised transaction ledger,” Ethereum project yellow paper, vol. 151, no. 2014, pp. 1–32, 2014.*


# SEN as the Heart of the Ecosystem

With SEN in the middle, we lower your fees, speed up your confirmation time, and so on.

In the DeFi market, the most common difficulty for an application is liquidity accumulation. Liquidity is an essential component to create a stable, reliable market, and attract users. Many DApps were struggling over the years to find liquidity, while a small number of top protocols took reign on almost all liquidity on the market.

Let’s examine a typical example for a swap on Solana. An LP deposits a set of SPL Token&#x73;*<mark style="color:purple;">\[10]</mark>* to a corresponding pool and receives an amount of LP tokens (LPT) according to their proportional contribution. In a way, LPT contains some values, so theoretically they can be exchanged or mortgaged. In the early era of DeFi, this point was usually skipped and LPT couldn’t be consumed.

To optimize the cash flow, a concept named **Yield Farming** has been introduced. It brought several advantages such as expanding cash flow, diversifying services, and bootstrapping liquidity. After staking LPT into a farm, LP also receives a farming token. Similar to the root problem, no service is available for farming tokens currently.

With an alternative approach, there are a number of lending & borrowing services that accept LPT as collateral to mint stable tokens. This solution is more creative and able to tackle the problem that farming has faced. A bottleneck here is that the number of accepted LPT is very limited due to assessment difficulty.*<mark style="color:purple;">\[11]</mark>*

By putting SEN in all pools, we can reduce the risk of fake tokens and accelerate the process of assessment for example. Now all fees can be converted to SEN. It’s very meaningful for the foundation to realize the concept “BuyBack and Make”. The foundation can allow a fraction of the fee to be converted to SEN and automatically transmitted to other services.

Now, SEN is regarded as a universal interface. Other services can rely on and leverage automated processes.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

*<mark style="color:purple;">\[10]</mark>* solana-labs, “[solana-labs/solana-program-library](https://github.com/solana-labs/solana-program-library),” 06 2020.

*<mark style="color:purple;">\[11]</mark> D. Lau, D. Lau, and S. Teh,* [*How to DeFi*](<https://books.google.nl/books?id=g6WazQEACAAJ >)*. Independently Published, 2020.*


# Asymmetric Deposit

Deposit Liquidity even with one-sided token pooling.

The Symmetric Deposit problem is that LPs must deposit the tokens in a pool with a predefined proportion. To remove extra actions, the algorithm in the AMM will automatically simulate the swap on the current pool to balance the amount for LPs. Then, the subsequent procedures like depositing and returning LP tokens are automated too. Because the process is just to simulate a single-sided deposit, we call it Simulated Single Exposure.

![Instead of preparing at least two types of token, users can now deposit even with only one type of token.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2Fm7eGrRVMAvKF9cKZRBiR%2FBanner-Day-5-asymemtric-22-10-2021%402x.png?alt=media\&token=cb3920d9-e76f-4df2-b5a0-cae87db1b840)

**Proposition 2.** Without loss of generality, giving a pool of $$A$$, $$B$$, and $$SEN$$ with the current state {$$R\_A,R\_B,R\_{SEN}$$}, an LP deposits $$\Delta\_{SEN}$$ to the pool and receives an amount of LP tokens $$lpt$$,

(16) $$lpt=\Delta\_{SEN}-(\delta\_A+\delta\_B)$$,

where $$\delta\_A+\delta\_B=\sqrt\[3]{R\_{SEN}(R\_{SEN}+\Delta\_{SEN})^2}-R\_{SEN}$$.

*Proof.* Let $$\Delta\_{SEN}=\delta\_A+ \delta\_B+\delta\_{SEN}$$, where the left term is the set of amounts of $$SEN$$ token to swap for {$$r\_A,r\_B,r\_{SEN}$$} in the simulation. The simulation is depicted by the following table (we use blackboard characters for state owners):

![](https://lh6.googleusercontent.com/Hwf-hRTZ1y389uBjRufbibxYz0DeBWFr_5UZpzqx3Vvbsh7_MkfN3Q9EP48zZQd-f_tCztfkNg4h8ELfMe8LW_3JmOyES5ocPKBCGf0BlquY7QNmPFhNPwCJ-_WgfT4TuwB0zWkM)

Here we don’t need to swap SEN, thus $$r\_{SEN}=\delta\_{SEN}$$. By the CPF (see Eq. (33)), we also know:

(17) $$R\_A'=\frac{R\_AR\_{SEN}}{R\_{SEN}+\delta\_A}$$,

(18) $$R'*B=\frac{R\_A(R*{SEN}+\delta\_A)}{R\_{SEN}+\delta\_A+\delta\_B}$$,

And:

(19) $$r\_A=R\_A-R'*A=\frac{R\_A\delta\_A}{R*{SEN}+\delta\_A}$$,

(20) $$r\_B=R\_B-R'*B=\frac{R\_B\delta\_B}{R*{SEN}+\delta\_A+\delta\_B}$$​.

To satisfy the symmetric deposit, we have a system of equations:

(21) $$\frac{r\_A}{R'*A}=\frac{r\_B}{R'*B}=\frac{r*{SEN}}{R*{SEN}+\delta\_A+\delta\_B}$$​.

Or,

(22) $$\frac{\delta\_A}{R\_{SEN}}=\frac{\delta\_B}{R\_{SEN}+\delta\_A}=\frac{\delta\_{SEN}}{R\_{SEN}+\delta\_A+\delta\_B}$$​.

By transforming the system of equations, we know that:

(23) $$\delta\_A+\delta\_B=\sqrt\[3]{R\_{SEN}(R\_{SEN}+\Delta\_{SEN})^2}-R\_{SEN}$$.

Therefore,  $$lpt=\delta\_{SEN}=\Delta\_{SEN}-(\delta\_A+\delta\_B).$$​


# Adaptive Fee Model

A model designed to free users from hefty fees while transacting.

Considering the CPF $${R\_A}\times{R\_B}=k$$, liquidity providers always incur a loss named **impermanent loss**, due to a state deviation of reserves. The loss will disappear if the state returns to the initial state. Without loss of generality, let’s assume that $$B$$ outperforms $$A$$ after a period. Clearly, arbitrageurs will sell $$A$$ to get $$B$$ because the current pool is maintaining an undervalued price of $$B$$.

(24) $$(R\_A,R\_B)\xrightarrow{0<\alpha\leq1}(\frac{1}{\alpha}R\_A,{\alpha}R\_B)$$.

Thus, the price is transforming from $$p=R\_B/R\_A$$ to $$p'=\alpha^2R\_B/R\_A$$. Compared with a *HODL* strategy, adding liquidity to a pool seems less profitable (without a fee model).

(25) $$loss\_{no-fee}=(p'R\_A+R\_B)-(p'\frac{1}{\alpha}R\_A+\alpha{R\_B})$$

(26) $$=(1-\alpha)^2R\_B.$$​

Most AMMs use a fee model typically of 0.25% to cover the loss. The mistake here is the fee is fixed while the loss is varied. It’s better when the fee is adaptive, that means the fee will be large if the loss is large, and vice versa.

To create a more effective fee model, the AMM develops a function $$\gamma=f(\alpha)$$, where $$0<\gamma\leq1$$, respects to $$\alpha$$ to adapt the change. Because $$\alpha$$ describes how the pool state deviates from the current state, it’s reasonable for the fee function to rely on $$\alpha$$.

![Fig. 3. Adaptive fee function: . Linear fee function: . Mixed fee function: . With fee models that are “above” the adaptive fee, the loss will be negative. The negative loss means liquidity providers are profitable.](https://lh5.googleusercontent.com/JidEF9fvUh2lCZ5iMPtjz8R1t_CUWYbOtwwG5JgSSD0MSyIUIJRTnu2DupjKnNafJpu-tUfHbf56Ilr0QLjGcFd_7hQim0AFf4GKJdVljEfLPb2iPYZY6kpAAPX612fcyP2mEXo8)

**Definition 2.** The impermanent loss is zero when the adaptive fee is following:

(27) $$\gamma=\frac{1-\alpha}{2-\alpha}$$.

*Proof.* Recall that a trader will get $$(1-\alpha)R\_B$$ in a no-fee model. When the AMM applies the adaptive fee model, the trader will receive $$(1 − \gamma)(1 − \alpha)R\_B$$. In summary,

(28) $$(R\_A,R\_B)\xrightarrow{0<\alpha,\gamma\leq1}(\frac{1}{\alpha}R\_A,{\alpha}R\_B+\gamma(1-\alpha)R\_B)$$.

With $$p'=\alpha(\alpha+\gamma(1-\alpha))R\_B/R\_A$$, the loss now is

(29 )$$loss\_{adaptive-fee}=(p'R\_A+R\_B)-(p'\frac{1}{\alpha}R\_A+\alpha+\gamma(1-\alpha))R\_B)$$​

(30) $$=((\alpha-2)(\alpha+\gamma(1-\alpha))+1)R\_B$$​.

Because of the zero loss, we have an equation, $$loss\_{adaptive-fee}=0$$​. Hence, $$\gamma=(1-\alpha)/(2-\alpha).$$​

**Corollary 1.** Applying the adaptive fee, the pool’s state will follow:

(31) $$(R\_A,R\_B)\xrightarrow{0<\alpha\leq1}(\frac{1}{\alpha}R\_A,\frac{1}{2-\alpha}R\_B).$$​

![TABLE I. The price change is equal to  The volume is determined over a $20mil-cap pool. Because the fee is relatively low regarding small price changes, the adaptive fee model and its variants are suitable for casual transactions.](https://lh3.googleusercontent.com/TW0Jt5sAENE6pqw3tQ5z2gTwWS4vPQKPpa9aNj6DQzdsX3sIJ4TeR-Aa7x88ykG1dJaCaYAVg6hCt3WCqGQ63DtJjH8Zfp344O8q8nf-8elJhf7tmwg6E6IRB0CXvb6xRCNXbKbb)

Because the pricing curve is the same as the 2D CPF, the impermanent loss (IL) is obvious to Sentre’s AMM too. However, employing a variant of the adaptive fee model can cover the IL while also benefit LPs.

(32) $$Protocol\ Fee=Adaptive\  Fee+0.05%$$

The approach can secure income for LPs. By flexibility, the fee is low corresponding to small price changes, and gets larger along with the price change.

Furthermore, the AMM collects a fractional fee as a tax to maintain the core engine at the beginning. In the future, this tax can be opened as a grant for community projects (see Fig. 4).

![Fig. 4. The fee is organized into two components. The adaptive fee represents the interest for LPs. The 0.05% is for Sentre Foundation to develop the core engine, grant liquidity to community projects, incubate innovative ideas, and so on.](https://lh4.googleusercontent.com/r58lzKq0fUp0jGwevLz9TIfb1hJsMoxh7QASLKHKPWKRfSA61SFdbPTEHZK6FNbteRxYNJG4YI6WgOrfJ31LKXjoWQZls489TRL-Brz_VD3YsH0ZM5ucO6eRmGkG1KrZZzLXMeYd)


# The Triad Pool

Swap any and every pairs. Never think about how you should divide your portfolio ever again.

Recall that the most well-adopted CPF is two-dimensional where $$R\_A\times{R\_B}=k$$. In Sentre, however, the pool can be optionally organized into three tokens. It’s now the pool of triad and the CPF turns to three-dimensional where the third dimension is for $$SEN$$ as in Fig. 5.

![Fig. 5. A visualization of the 3D CPF.](https://lh3.googleusercontent.com/fO5NVw3oYzA1e2V-B99CFkzTPOzquICEsSRoWPhohkaz3M5wSNMz43V-PVOOPo_Pm3IUAyeYy8sUT7ebg_bOuu5QVzhDDiXjrRn2zlSFk5QuG7g8LP2WTKucLiEogl1u8MC_751v)

***Definition 3.** For a pool of* $$A$$, $$B$$, *and compulsory* $$SEN$$*, the 3D constant product function is:*

*(33)* $$R\_A\times{R\_B}\times{R\_{SEN}}=k$$*​,*

*where* $$k$$ *is a constant.*

To deposit to the pool, a liquidity provider (LP) theoretically needs to divide their portfolio into three equal portions regarding value. However, LPs never worry about this due to **Simulated Single Exposure** which allows people to deposit even on one side (see [*Asymmetric Deposit*](/litepaper/sen-as-the-heart-of-the-ecosystem/asymmetric-deposit)). Especially, although the formula has a higher dimension, the formula isn’t much different from the 2D CPF in trading.

When a trader swaps $$A$$ from $$B$$, for example, the third token, which is $$SEN$$​ in this case, will be ignored. The formula is boiled down to $$R\_A\times{R\_B}=\frac{k}{R\_{SEN}}=k'$$​, where $$k'$$ is a constant as well.

Assume a trader swaps  $$r\_A$$ for $$r\_B$$, the newest state of token $$A$$ would be $$R'\_A=R\_A+r\_A$$​. Because of the CPF, we have:

(34) $$R'\_B=\frac{R\_AR\_B}{R'\_A}=\frac{R\_AR\_B}{R\_A+r\_A}$$.


# Simulated Mesh Trading

Since *SEN* can be enabled in all pools within Sentre protocol, all tokens will be exchanged through *SEN* if no direct pool is found. Therefore, the number of routes is always less than 2. We call it **Simulated Mesh Trading** due to the dependency on SEN. This property reminds us of Uniswap v1.


# Token Use Cases

What can you do with $SEN and why should you HODL it?

As the Heart of Sentre’s ecosyste&#x6D;*<mark style="color:purple;">\[12]</mark>*, SEN possesses some of the most beneficial use cases for long holders, namely:

![As the Heart of Sentre’s ecosystem, SEN possesses some of the most beneficial use cases for long holders.](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2FXXoLvBrCaxHDs6rVeSaP%2FBanner-Day-5-22-10-2021%402x.png?alt=media\&token=4eb023e8-b2fb-448a-b42c-70738d48bd3c)

## Governance Rights

To propose an on-chain improvement, participants need to stake SEN in order to vote and reach a consensus. The ratified proposals will be implemented and deployed by the foundation team. For example, as Sentre is an open liquidity protocol, if any new project wants to inherit liquidity from Sentre then SEN holders can vote to choose whether or not this dApp project is worth it.

## Fee Reduction

SEN helps reduce and maintain an upper bound of the exchange fee. When swapping, with SEN as the “bridge” between any pair of tokens, users can reduce the exchange rate from 0.3% to only 0.25%.

## Buyback and Make

SEN is designed as a fee collector. With any swapped pair, the fee can be easily transformed into SEN. Then, instead of burning them away, these fees are collected and automatically transmitted to other SEN-based services.

## Protocol Entrepôt

SEN connects all pools in the ecosystem and makes sure any pair of tokens can be swapped. Putting SEN into all existing two-token pools on SenSwap helps users focus all liquidity into one pool instead of having to deposit into three different pools. This increases liquidity effectiveness and reduces the hassle of having to balance between three pairs of tokens when depositing.

As SEN is present in any and every pool, there is no token that can’t be converted into SEN. Therefore, any pair of tokens, no matter how exotic and rare, can be swapped by simply converting both into SEN. Other tokens can also be evaluated via SEN for the same technique.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

*<mark style="color:purple;">\[12]</mark> In cases where SEN is enabled to be active in triad pools.*


# Conclusion

In summary, we conducted a slight comparison (see table II) among Sentre, Uniswap, and PancakeSwap.

![TABLE II](https://lh3.googleusercontent.com/rLLbog_x8hXXaj7gGyEi4WIs6XlO6AE6xC1evLdgosNNIxw_iVUPZrIj_oKGRtSQzYT1Yx3EbrSAyHjzuP-OrgOIVBrLTlkVyn2rIWAeVh0As1gp1tPETFiRhff4GGUL2dOjj8Ma)

Sentre pursues an aspiration beyond DeFi. Sentre heads toward an Open Finance solution that increases accessibility, optimizes the liquidity effectiveness, and brings more value to users, while creating a supportive environment for developers to innovate. Meaningful projects can instantly access technical resources and essential liquidity for their success.

The more open, the more innovative.

![](https://3606779243-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDSuDatsiBSDcGYiS7br6%2Fuploads%2F39QfA11pUxXdafNacmMX%2FCover%20Twitter.png?alt=media\&token=d69079f0-9d0f-405c-8f32-c343cd8e87c6)

Connect with Sentre for more information and benefits, designed for you:

[Website](<https://sentre.io/ >) | [Medium](https://sentre.medium.com) | [Telegram Community](<https://t.me/Sentre >) | [Indonesian Community](<https://t.me/SentreIndonesia >) | [Telegram Announcements](<https://t.me/SentreAnnouncements >) | [Twitter Announcements](<https://twitter.com/SentreProtocol >) | [Discord Community](<https://discord.com/invite/VD7UBAp2HN >)


