# TVM Connect

Create a connection to Nekoton-based wallets and dApps

## Usage

### Installation

To apply this component, install it with **npm** using following command:

```shell
npm install @broxus/tvm-connect
```

or using **yarn**:

```shell
yarn add @broxus/tvm-connect
```

### Requirements

In general it works great with our [UIkit](https://www.npmjs.com/package/@broxus/react-uikit) package.
If you use this package you don't need to worry about the details.

#### Minimum requirements

If you are only going to use stores, you should install a few required packages

```shell
npm i everscale-inpage-provider mobx
```

or using **yarn**:

```shell
yarn add everscale-inpage-provider mobx
```

#### Full requirements

If you would like to use stores and included react components, you need to install a few more packages

```shell
npm i everscale-inpage-providermobx mobx-react-lite react-intl
```

or using **yarn**:

```shell
yarn add everscale-inpage-provider mobx-react-lite react-intl
```

### TvmWalletService

The Wallet Service is a key part of this module. It accepts a number of settings and
parameters when created and has a convenient interface for working with a connected wallet.
It works with wallets whose providers and standalone RPC connections are
based on `everscale-inpage-provider` and `everscale-standalone-client`.

```typescript
import { TvmChains } from '@broxus/js-core'
import { EverWallet, SparXWallet, TvmWalletProviderConfig, TvmWalletService, VenomWallet } from '@broxus/tvm-connect'

const sparxWallet: TvmWalletProviderConfig = {
    connector: new SparXWallet(), // autoInit: false to prevent auto initialization. Optional
    id: 'SparXWallet',
    info: {
        description: 'Your universal tool for TVM',
        icon: '/assets/icons/SparXWallet.svg',
        links: {
            android: 'https://play.google.com/store/apps/details?id=com.broxus.sparx.app',
            homepage: 'https://sparxwallet.com/',
            ios: 'https://apps.apple.com/us/app/sparx-tvm-wallet/id6670219321',
        },
        name: 'SparX Wallet',
    },
}
const everWallet: TvmWalletProviderConfig = {
    connector: new EverWallet({ autoInit: false }), // autoInit: false to prevent auto initialization. Optional
    id: 'EverWallet',
    info: {
        description: 'Premier wallet for the Everscale',
        icon: '/assets/icons/EverWallet.svg',
        links: {
            android: 'https://play.google.com/store/apps/details?id=com.broxus.crystal.app',
            chromeExtension: 'https://chrome.google.com/webstore/detail/ever-wallet/cgeeodpfagjceefieflmdfphplkenlfk',
            firefoxExtension: 'https://addons.mozilla.org/en-GB/firefox/addon/ever-wallet/',
            homepage: 'https://everwallet.net/',
            ios: 'https://apps.apple.com/us/app/ever-wallet-everscale/id1581310780',
        },
        name: 'Ever Wallet',
    },
}
const venomWallet: TvmWalletProviderConfig = {
    connector: new VenomWallet(),
    id: 'VenomWallet',
    info: {
        description: 'Safe, reliable, and 100% yours',
        icon: '/assets/icons/VenomWallet.svg',
        links: {
            android: 'https://play.google.com/store/apps/details?id=com.venom.wallet',
            chromeExtension: 'https://chrome.google.com/webstore/detail/venom-wallet/ojggmchlghnjlapmfbnjholfjkiidbch',
            homepage: 'https://venomwallet.com/',
            ios: 'https://apps.apple.com/app/venom-blockchain-wallet/id1622970889',
        },
        name: 'Venom Wallet',
    },
}

const walletService = new TvmWalletService({
    autoInit: false,
    defaultNetworkId: TvmChains.EverscaleMainnet, // 42
    networks: [
        {
            chainId: TvmChains.EverscaleMainnet.toString(),
            currency: {
                decimals: 9,
                icon: '/assets/icons/EVER.svg',
                name: 'Native currency',
                symbol: 'EVER',
                wrappedCurrencyAddress: new AddressLiteral(
                    '0:a49cd4e158a9a15555e624759e2e4e766d22600b7800d891e46f9291f044a93d'), // WEVER
            },
            explorer: {
                accountsSubPath: 'accounts',
                baseUrl: 'https://everscan.io',
                title: 'EVER Scan',
                transactionsSubPath: 'transactions',
            },
            id: `tvm-${TvmChains.EverscaleMainnet.toString()}`, // <type>-<chainId>
            name: 'Everscale',
            rpcUrl: 'https://jrpc.everwallet.net',
            shortName: 'Everscale',
            type: 'tvm',
        },
    ],
    providerId: 'EverWallet', // TvmWalletProviderConfig['id']
    providers: [sparxWallet, everWallet, venomWallet],
})

await everWallet.connector.init()
const provider = await walletService.init()
await walletService.connect()
```

> This is library/framework agnostic component. So, you can use it anywhere.

## Using with React

First at all, you should wrap entire your app with `TvmWalletServiceProvider` to share `TvmWalletService`
through all your app components.

```typescript jsx
import { TvmConnector, TvmWalletServiceProvider } from '@broxus/tvm-connect'
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { IntlProvider } from 'react-intl'

function App(): JSX.Element {
    return (
        <IntlProvider>
            <TvmWalletServiceProvider>
                ...
                <TvmConnector />
                ...
            </TvmWalletServiceProvider>
        </IntlProvider>
    )
}

ReactDOM.render(<App />, document.body)
```

## Custom service

You may use `TvmWalletService` to create your own service with provider and connection.

```typescript jsx
import { TvmWalletService } from '@broxus/tvm-connect'

let service: TvmWalletService

export function useTvmConnect(): TvmWalletService {
    if (service === undefined) {
        service = new TvmWalletService({
            defaultNetworkId: number, // (optional) use TvmChains enum to provide a network id
            networks: TvmNetworkConfig[], // (optional) supported networks configurations
            providerId: string, // (optional) TvmWalletProviderConfig['id'] provide option to define a default connector
            providers: TvmWalletProviderConfig[], // (optional) providers config
        })
    }
    return service
}

// Pass custom wallet to service provider
function App(): JSX.Element {
    const wallet = useTvmConnect()
    return (
        <IntlProvider>
            <TvmWalletServiceProvider wallet={wallet}>
            ...
                <TvmConnector />
            ...
            </TvmWalletServiceProvider>
        </IntlProvider>
    )
}
```

### Network configuration

Below you can see a models of the network configuration, native currency and explorer config.

```typescript
interface NativeCurrency<T = any> {
    balance?: string
    decimals: number
    icon?: string
    name?: string
    symbol: string
    wrappedCurrencyAddress?: T
}


interface TvmNetworkConfig {
    badge?: string
    chainId: string
    currency: NativeCurrency<Address>
    disabled?: boolean
    explorer: NetworkExplorerConfig
    icon?: string
    id: string
    name: string
    rpcUrl: string
    shortName: string
    tokensListUri?: string
    tokenType?: string
    type: 'tvm'
}

interface NetworkExplorerConfig {
    accountsSubPath?: string | null
    baseUrl: string
    title: string
    tokensSubPath?: string | null
    transactionsSubPath?: string | null
}
```

### Provider configuration

To use more providers (wallets) and their connections, you can configure these providers with
the `providers` option that can be passed when instantiating the `TvmWalletService`.

```typescript
interface TvmWalletProviderConfig {
    connector: NekotonConnector
    info: {
        description?: string
        icon?: string
        links?: TvmProviderPlatformLinks & { homepage?: string, universalLink?: string }
        name: string
    }
    id: string
    isRecent?: boolean
    minVersion?: string
}

export type TvmProviderAvailablePlatforms = 'ios' | 'android' | 'chromeExtension' | 'firefoxExtension'

export type TvmProviderPlatformLinks = Partial<Record<TvmProviderAvailablePlatforms, string>>
```

## Helpful utils
You can use `isEverWalletBrowser` or `isVenomWalletBrowser` to check environment.

- `isSparXWalletBrowser` - checks if your dApp is opened in mobile SparX Wallet WebView
- `isEverWalletBrowser` - checks if your dApp is opened in mobile Ever Wallet WebView
- `isVenomWalletBrowser` - checks if your dApp is opened in mobile Venom Wallet WebView

This will help you determine which connectors to use for mobile applications and for all other cases

```typescript
import { TvmChains } from '@broxus/js-core'
import { TvmWalletService, useRecentConnectionMeta } from '@broxus/tvm-connect'
import { AddressLiteral } from 'everscale-inpage-provider'

const providers: TvmWalletProviderConfig[] = []

const networks: TvmNetworkConfig[] = [
    {
        chainId: TvmChains.EverscaleMainnet.toString(),
        currency: {
            decimals: 9,
            icon: '/assets/icons/EVER.svg',
            name: 'EVER',
            symbol: 'EVER',
            wrappedCurrencyAddress: new AddressLiteral('0:a49cd4e158a9a15555e624759e2e4e766d22600b7800d891e46f9291f044a93d'),
        },
        explorer: {
            accountsSubPath: 'accounts',
            baseUrl: 'https://everscan.io',
            title: 'EVER Scan',
            transactionsSubPath: 'transactions',
        },
        icon: '/assets/icons/EVER.svg',
        id: `tvm-${TvmChains.EverscaleMainnet}`,
        name: 'Everscale',
        rpcUrl: 'https://jrpc.everwallet.net',
        shortName: 'Everscale',
        type: 'tvm',
    },
    {
        chainId: TvmChains.VenomMainnet.toString(),
        currency: {
            decimals: 9,
            icon: '/assets/icons/VENOM.svg',
            name: 'VENOM',
            symbol: 'VENOM',
            wrappedCurrencyAddress: new AddressLiteral('0:77d36848bb159fa485628bc38dc37eadb74befa514395e09910f601b841f749e'),
        },
        explorer: {
            accountsSubPath: 'accounts',
            baseUrl: 'https://venomscan.com',
            title: 'VenomScan',
            transactionsSubPath: 'transactions',
        },
        icon: '/assets/icons/VENOM.svg',
        id: `tvm-${TvmChains.VenomMainnet}`,
        name: 'Venom Mainnet',
        rpcUrl: 'https://jrpc.venom.foundation',
        shortName: 'Venom',
        type: 'tvm',
    },
]

try {
    const ua = getUserAgent()
    const isSparXWallet = isSparXWalletBrowser(ua)
    const isEverWallet = isEverWalletBrowser(ua)
    const isVenomWallet = isVenomWalletBrowser(ua)
    if (isSparXWallet) {
        providers.push(sparxWallet)
        defaultProviderId = sparxWallet.id
        predefinedNetworkId = TvmChains.EverscaleMainnet
    }
    else if (isEverWallet) {
        providers.push(everWallet)
        defaultProviderId = everWallet.id
        predefinedNetworkId = TvmChains.EverscaleMainnet
    }
    else if (isVenomWallet) {
        providers.push(venomWallet)
        defaultProviderId = venomWallet.id
        predefinedNetworkId = TvmChains.VenomMainnet
    }
    else {
        providers.push({
            ...sparxWallet,
            minVersion: '0.4.0',
        }, {
            ...everWallet,
            minVersion: '0.4.0',
        }, {
            ...venomWallet,
            minVersion: '0.3.173',
        })
    }
}
catch (e) {}

let service: TvmWalletService

export function useTvmWallet(): TvmWalletService {
    const [recentMeta] = useRecentConnectionMeta()
    if (service === undefined) {
        const networkId = recentMeta?.chainId ? Number(recentMeta.chainId) : TvmChains.EverscaleMainnet
        service = new TvmWalletService({
            defaultNetworkId: predefinedNetworkId ?? networkId,
            networks,
            providerId: recentMeta?.disconnected ? defaultProviderId : recentMeta?.providerId ?? defaultProviderId,
            providers,
        })
    }
    return service
}
```

## Styling

If you are using our [UIkit](https://www.npmjs.com/package/@broxus/react-uikit) package it will it automatically adapts to your interface colors.

Otherwise, you can import standalone CSS

```typescript jsx
import '@broxus/tvm-connect/uikit.min.css' // include all required styles from UIkit
import '@broxus/tvm-connect/style.min.css' // include all required styles from TVM Connect
```
Below you can find all supported CSS variables and their defaults

```css
/* Connector */
--tvm-connect-dropdown-trigger-horizontal-padding: var(--global-small-gutter, 8px);
--tvm-connect-dropdown-trigger-vertical-padding: 0;
--tvm-connect-dropdown-background: var(--dropdown-background, #fff);
--tvm-connect-dropdown-border-radius: var(--dropdown-border-radius, 5px);
--tvm-connect-dropdown-box-shadow: 0 8px 32px 0 rgb(63 74 111 / 12%), 0 1px 4px 0 rgb(63 74 111 / 8%);
--tvm-connect-dropdown-color: var(--dropdown-color, #333);
--tvm-connect-dropdown-link-color: var(--dropdown-color, #0af);

/* Providers list buttons */
--tvm-connect-provider-button-border-width: 2px;
--tvm-connect-provider-button-border-style: solid;
--tvm-connect-provider-button-border: transparent;
--tvm-connect-provider-button-hover-border: var(--global-primary-border, transparent);

/* Modal */
--tvm-connect-modal-content-background: var(--modal-content-background, #fff);
--tvm-connect-modal-content-border-radius: 12px;
--tvm-connect-modal-content-box-shadow: 0 8px 32px 0 rgb(63 74 111 / 12%), 0 1px 4px 0 rgb(63 74 111 / 8%);
--tvm-connect-modal-content-color: var(--base-body-color, #383838);
--tvm-connect-modal-content-padding-horizontal: 18px;
--tvm-connect-modal-content-padding-vertical: var(--tvm-connect-modal-content-padding-horizontal);
--tvm-connect-modal-header-padding-horizontal: 0;
--tvm-connect-modal-header-padding-vertical: var(--tvm-connect-modal-content-padding-vertical);
--tvm-connect-modal-title-color: var(--base-heading-color, #383838);
--tvm-connect-modal-title-font-size: var(--modal-title-font-size, 18px);
--tvm-connect-modal-title-font-weight: 500;
--tvm-connect-modal-title-line-height: var(--modal-title-line-height, 22px);
--tvm-connect-modal-body-padding-horizontal: 0;
--tvm-connect-modal-body-padding-vertical: var(--tvm-connect-modal-content-padding-vertical);
--tvm-connect-modal-footer-padding-horizontal: 0;
--tvm-connect-modal-footer-padding-vertical: var(--tvm-connect-modal-content-padding-vertical);

/* Drawer */
--tvm-connect-drawer-content-background: var(--drawer-content-background, #fff);
--tvm-connect-drawer-content-border-radius: 16px;
--tvm-connect-drawer-content-box-shadow: 0 8px 32px 0 rgb(63 74 111 / 12%), 0 1px 4px 0 rgb(63 74 111 / 8%);
--tvm-connect-drawer-content-color: var(--base-body-color, #383838);
--tvm-connect-drawer-content-padding-horizontal: 24px;
--tvm-connect-drawer-content-padding-vertical: var(--tvm-connect-drawer-content-padding-horizontal);
--tvm-connect-drawer-header-padding-horizontal: 0;
--tvm-connect-drawer-header-padding-vertical: var(--tvm-connect-drawer-content-padding-vertical);
--tvm-connect-drawer-title-color: var(--base-heading-color, #383838);
--tvm-connect-drawer-title-font-size: var(--drawer-title-font-size, 24px);
--tvm-connect-drawer-title-font-weight: 500;
--tvm-connect-drawer-title-line-height: var(--drawer-title-line-height, 28px);
--tvm-connect-drawer-body-padding-horizontal: 0;
--tvm-connect-drawer-body-padding-vertical: var(--tvm-connect-drawer-content-padding-vertical);
--tvm-connect-drawer-footer-padding-horizontal: 0;
--tvm-connect-drawer-footer-padding-vertical: var(--tvm-connect-drawer-content-padding-vertical);

/* Connection approve popup stage */
--tvm-connect-connection-request-button-border-width: 2px;
--tvm-connect-connection-request-button-border-style: solid;
--tvm-connect-connection-request-button-border: transparent;
--tvm-connect-connection-request-button-hover-border: var(--global-border, transparent);
```
