UNPKG

@broxus/tvm-connect

Version:

Nekoton-compatible wallets connector.

460 lines (393 loc) 15.9 kB
# 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); ```