ethers-svelte
is a package that integrates the ethers.js v6
library as a collection of readable Svelte
stores for Svelte or SvelteKit. It
provides a convenient and reactive way to interact with Ethereum blockchain
using ethers.js in your Svelte applications.
Key features:**
- A set of reactive Svelte stores, automatically updated when a new connection, or when the chain or the selected account changes
- Support for ethers.js version 6, with compatibility for various EVM providers (such as browser wallets like Metamask, WalletConnect, Web3Modal, web3-onboard and more)
- A few basic Svelte components for typical ethers.js usage, such as
Balance
,Identicon
, andJazzicon
, demonstrating how it is easy to build common UI elements in your application.
With ethers-svelte
, you can quickly set up connections to Ethereum blockchain,
manage accounts and contracts, and create reactive UI components that respond to
changes in the underlying blockchain data. This package simplifies the process
of building decentralized applications using Svelte or SvelteKit (Sapper should
also works but it's official support is now deprecated).
ethers-svelte
support ethers.js
version 6. If you want the same package for
ethers.js
version 5, please use the package
svelte-ethers-store.
If you also use the web3.js library to interact with EVM, you may be interested by the sister package svelte-web3.
For additional help or discussion, join us in our Discord.
To use ethers-svelte
in your Svelte or SvelteKit project, you need to add it
as a dependency:
npm i ethers-svelte
Once the package is installed, you can import and use the provided stores and components in your application, as shown in the Basic Usage and Ethers Svelte Components sections.
In this section, we will cover how to use the default stores provided by
ethers-svelte
for managing a single chain connection. The default stores
include connected
, provider
, chainId
, chainData
, signer
,
signerAddress
, and contracts
.
ethers-svelte
provides a set of readable Svelte stores that automatically
update when a new connection is established, or when the chain or selected
account changes. Import the required stores in your Svelte or JavaScript files:
import {
connected,
provider,
chainId,
chainData,
signer,
signerAddress,
contracts,
} from "ethers-svelte"
- connected: store value is true if a connection has been set up.
- provider: store value is an Ethers.js Provider instance when connected.
- chainId: store value is the current chainId when connected (** always a BigInt **)
- chainData: store value is the current blokchain CAIP-2 data (when connected), see below.
- signer: store value is an Ethers.js Signer instance when connected.
- signerAddress: store value is a shortcut to get
$signer.getAddress()
when connected. - contract: store value is an Object for all ethers.Contract instances you need.
To make these stores useful in your Svelte application, you first need to
establish a connection to an EVM blockchain. Use the defaultEvmStores
helper
to initiate the connection and instantiate all stores:
import { defaultEvmStores } from "ethers-svelte"
To enable a connection with the current EIP-1193
provider
injected into the browser's window
context, simply call the setProvider()
method on the defaultEvmStores
helper without any arguments:
defaultEvmStores.setProvider()
Please note that using setProvider()
without any arguments is only possible in
a browser context. When using SvelteKit, you may want to use the onMount
function. Similarly, you cannot use setProvider
with no argument in SSR
context.
import { onMount } from "svelte"
onMount(() => {
// Add a test to return in SSR context
defaultEvmStores.setProvider()
})
ethers-svelte
will automatically update the stores when the network or
accounts change, and it will remove listeners upon disconnection.
It's common to abbreviate the defaultEvmStores
helper in applications. For
example, you can use a evm
shortcut alias as shown in the following example.
This documentation will use this convention going forward.
import {
defaultEvmStores as evm,
} from "ethers-svelte"
// ...
evm.setProvider()
By using the evm
alias, you can simplify your code and make it easier to read
while still retaining the functionality provided by the defaultEvmStores
helper. This convention allows for cleaner code organization and improved
readability in your Ethereum-based applications.
For non-injected EIP-1193 providers like:
- buidler.dev
- ethers.js
- eth-provider
- WalletConnect
- Web3Modal
- Web3 Onboard
Call the setProvider()
method on the evm
helper with the
JavaScript provider instance object of the library. For example, with Web3Modal:
const web3Modal = new Web3Modal(<your config>)
const provider = await web3Modal.connect()
evm.setProvider(provider)
ethers-svelte
will automatically update the stores when the network or
accounts change, and it will remove listeners upon disconnection.
You can instantiate various types of providers using Ethers.js (see the
relevant documentation)
and pass them as an argument to evm.setProvider()
to initiate the
stores:
evm.setProvider(new ethers.InfuraProvider(<args>))
// or
evm.setProvider(new ethers.EtherscanProvider(<args>))
// or
evm.setProvider(new ethers.AlchemyProvider(<args>))
// etc...
As a shortcut, if you pass a URL string or a valid connection object, an Ethers.js JsonRpcProvider will be automatically instantiated.
For providers that support the getSigner()
function, a Signer Object will be
automatically associated with the signer
store. You can also pass
addressOrIndex
as the second argument of setProvider()
to select another
account than the default when possible.
evm.setProvider(<Ethers provider>, <addressOrIndex>)
If you don't need a signer, you might also call setProvider()
with the
argument addressOrIndex
set to null
, which will bypass any attempt to detect
an account.
After a connection has been established, you can import the stores anywhere in
your application. Most of the time, you should use the $
prefix Svelte
notation to access the store values.
<script>
import { connected, chainId, signerAddress } from "ethers-svelte"
</script>
{#if !$connected}
<p>My application is not yet connected</p>
{:else}
<p>Connected to chain (id {$chainId}) with account ($signerAddress)</p>
{/if}
The example above allows you to display connection status, chain ID, and signer address in your application based on the current connection state.
As you build your application, you can use these stores to create reactive UI components that respond to changes in the underlying blockchain data.
To leverage the full functionality of Ethers.js Providers and Signers within
your Svelte application, use the $
prefix Svelte notation to access the
provider
and signer
stores. This allows you to call methods from the
Ethers.js API directly.
For example, you can interact with the blockchain using the following Ethers.js methods:
import { connected, provider, signer } from "ethers-svelte"
// ...
const { name, chainId } = await $provider.getNetwork()
const balance = await $signer.getBalance()
$signer.sendTransaction({ to: <recipient>, value: <amount>, gasLimit: <gasLimit> })
Remember that for providers that don't support getSigner
, the value of
$signer
will be null
.
By using the $
notation to access the provider
and signer
instances, you
can ensure that your application's UI components will react to any changes in
the underlying blockchain data. This simplifies the process of creating and
managing decentralized applications using Svelte.
The contracts
store allows you to interact with smart contracts reactively by
declaring their address, ABI, and an optional logical name. To do this, use the
attachContract()
function provided by evm
.
<script>
import { defaultEvmStores as evm } from "ethers-svelte"
// ...
evm.attachContract("myContract", <address>, <abi>)
</script>
The attachContract()
function only needs to be called once and can be called
before a connection is established. Ethers.Contract
instances will be created
when a connection becomes available. If you want to reattach a new contract
definition or ABI when the current network changes, simply use the same logical
name. The old definition will be overwritten, and the instance updated in the
contracts
store.
After declaring a contract, you can access its instance anywhere in your
application using the $
notati*on and the logical name:
<script>
import { contracts } from "ethers-svelte"
// ...
</script>
{#await $contracts.myContract.totalSupply()}
<span>waiting...</span>
{:then value}
<span>Result of contract call totalSupply on my contract: {value}</span>
{/await}
By default, ethers-svelte
builds contract instances using the signer if
available and the provider otherwise. You can force the use of the current
provider by passing false
as the fourth argument to attachContract()
.
evm.attachContract('myContract', <address>, <abi>, false)
By using the $contracts
store, you can create reactive UI components that
interact with smart contracts and automatically update when the underlying
contract state changes.
When working with pure JavaScript files outside of Svelte components, you cannot
use the $
prefix notation to access store values directly. Instead, you can
use the $<store>
method provided by the defaultEvmStores/evm
helper to access
the instantiated values without subscribing to the store:
// this is not a Svelte file but a standard JavaScript file
import { defaultEvmStores as evm } from "ethers-svelte"
if (evm.$selectedAccount)) {
// Do something if the store selectedAccount is non-null
}
You can use the $<store>
methods with any of the available store names, such
as connected
, provider
, chainId
, chainData
, signer
, signerAddress
,
and contracts
.
There might be situations where you want to disconnect from the current provider
and remove all associated listeners. To achieve this, simply call the
disconnect()
method on the defaultEvmStores/evm
helper:
evm.disconnect()
This method will reset the connection state, remove all listeners, and update the store values accordingly. You can use this method, for example, when your application needs to switch between different providers or when the user logs out.
By disconnecting and removing listeners, you can ensure that your application remains responsive to user actions and maintains a clean state when transitions occur between providers or user sessions.
The chainData
store provides human-readable information about the currently
connected chain in the
CAIP-2
format. This information can be useful for displaying details about the
connected chain and updating UI elements reactively.
To access the chain data, simply import and use the chainData
store:
import { chainData } from "ethers-svelte"
The information returned by the chainData
store depends on the connected
chain. If the store has not yet been connected (with setProvider()
), the store
value will be an empty Object.
The following is an example of the CAIP-2 formatted information when the default
store is connected to the Ethereum Mainnet. The chainData
store will return an
object containing various information about the connected chain, such as its
name, chain ID, native currency, and more.
You can use this information to display relevant details about the connected chain in your application and update your UI reactively based on the current chain data.
{
"name": "Ethereum Mainnet",
"chain": "ETH",
"icon": "ethereum",
"rpc": [
"https://mainnet.infura.io/v3/${INFURA_API_KEY}",
"https://api.mycryptoapi.com/eth"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://ethereum.org",
"shortName": "eth",
"chainId": 1,
"networkId": 1,
"slip44": 60,
"ens": { "registry": "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" },
"explorers": [
{
"name": "etherscan",
"url": "https://etherscan.io",
"standard": "EIP3091"
}
]
}
If you want to access all chains CAIP-2 data directly without using the
chainData
store, you can use the allChainsData
getter. It returns the list
of all available CAIP-2 data.
import { allChainsData } from "ethers-svelte"
console.log(allChainsData)
Alternatively, you can use the getChainDataByChainId
helper function, which
takes the chainId
as an argument and returns the corresponding CAIP-2 data or
an empty object if not found.
import { getChainDataByChainId } from "ethers-svelte"
console.log(getChainDataByChainId(5))
These methods allow you to access chain-specific information without relying on
the reactive chainData
store, making it easier to work with multiple chains or
retrieve data outside of Svelte components.
ethers-svelte
includes several basic Svelte components designed to simplify
common tasks when building Ethereum-based applications. These components
demonstrate how to use the ethers-svelte
library effectively and serve as
reusable and composable best practices components. Currently, the library
includes Balance
, Identicon
, and Jazzicon
components. We encourage
community members to contribute and help develop additional components by
joining our discussions in our Discord.
You can find example usage of these components in the components
route in the
example directory.
The Balance
component displays the balance of a specified Ethereum address. To
use the Balance
component, import it and pass the address as a prop:
<script>
import { Balance } from 'ethers-svelte/components'
</script>
<p>Balance: <Balance address="0x0000000000000000000000000000000000000000" /></p>
The Identicon
component generates a unique identicon (a visual representation
of an Ethereum address) using the ethereum-blockies-base64
library. To use the
Identicon
component, import it and pass the address as a prop:
<script>
import { Identicon } from 'ethers-svelte/components'
</script>
<Identicon address="0x0000000000000000000000000000000000000000" />
The Jazzicon
component generates a unique and colorful identicon using the
@metamask/jazzicon
library. To use the Jazzicon
component, import it and
pass the address and size (optional) as props:
<script>
import { Jazzicon } from 'ethers-svelte/components'
</script>
<Jazzicon address="0x0000000000000000000000000000000000000000" size={32} />
These components serve as a starting point for building your Ethereum-based
applications using ethers-svelte
. You can further customize them and create
additional components according to your application's requirements. By
leveraging the reactivity and simplicity of Svelte along with the powerful
features of ethers.js, you can create a seamless and efficient user experience
for your decentralized applications.
Auto-connecting on page load is outside the scope of this package. However, the
implementation depends on the type of provider you are using and a method to
store connection information between page loads (e.g., using localStorage). You
can create a custom function that connects to your desired provider and calls
evm.setProvider()
on page load.
Yes, you can create multiple instances of EVM stores by calling
makeEvmStores(name)
with a unique name for each instance. This allows you to
manage connections, accounts, and contracts for different chains independently.
Yes, ethers-svelte
works with both Sapper and SvelteKit. However, Sapper suppory
is not officially supported and when using setProvider()
with no arguments in
a server-side rendering (SSR) context, you should use the onMount
lifecycle
function to ensure it is called only in the browser context.
Yes, you can refer to the Rouge Ticket application, which demonstrates the
integration of ethers-svelte
and Web3 Onboard. The wallet configuration can be
found in the wallet.js
file:
https://github.com/TheRougeProject/ticket-dapp/blob/main/src/lib/wallet.js
This example will help you understand how to use ethers-svelte
in conjunction
with Web3 Onboard to build a seamless and user-friendly Ethereum application.