Create a connection to Nekoton-based wallets and dApps
To apply this component, install it with npm using following command:
npm install @broxus/tvm-connect
or using yarn:
yarn add @broxus/tvm-connect
In general it works great with our UIkit package. If you use this package you don't need to worry about the details.
If you are only going to use stores, you should install a few required packages
npm i everscale-inpage-provider mobx
or using yarn:
yarn add everscale-inpage-provider mobx
If you would like to use stores and included react components, you need to install a few more packages
npm i everscale-inpage-providermobx mobx-react-lite react-intl
or using yarn:
yarn add everscale-inpage-provider mobx-react-lite react-intl
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
.
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.
First at all, you should wrap entire your app with TvmWalletServiceProvider
to share TvmWalletService
through all your app components.
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)
You may use TvmWalletService
to create your own service with provider and connection.
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>
)
}
Below you can see a models of the network configuration, native currency and explorer config.
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
}
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
.
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>>
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
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
}
If you are using our UIkit package it will it automatically adapts to your interface colors.
Otherwise, you can import standalone CSS
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
/* 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);