Skip to main content

SDK with ethers

ethers is arguably the most popular and widely used Ethereum JavaScript library. You can spot it in almost any popular DApp. If your DApp doesn't leverage a high-level state management library like web3-react but solely relies on ethers for the most basic wallet connections, our Ruby One SDK fully supports it. This tutorial demonstrates how to connect Ruby One using just ethers.

tip

The latest version of ethers is 6.x. It underwent significant refactoring compared to its predecessor, version 5.x. The two versions are not compatible. In this example, we will be using the latest 6.x version.

This example parallels the functionality of the previous tutorial about web3-react. Most of the code remains the same, so this article will omit some detailed explanations for brevity.

Create a React Project

pnpm create vite rubyone-ethers --template react-ts

Install dependencies:

cd rubyone-ethers
pnpm install @rubyone/jssdk react-toastify ethers

Here, we didn't specify the ethers version, meaning the latest 6.x will be installed.

Creating a Provider

This step is identical to our previous example. Code the following in the sdk.ts file:

import { RubyOneProvider } from '@rubyone/jssdk'

const rubyOneProvider = new RubyOneProvider()
export default rubyOneProvider

Configure Connector

This step majorly differs from web3-react. In the prior example, we relied on web3-react's initializeConnector to create an EIP1193 connector. However, with ethers, we'll utilize BrowserProvider to achieve a similar goal. Here's the core code:

import { BrowserProvider } from 'ethers'

const provider = new BrowserProvider(rubyOneProvider)

Write the Hook

The basic functionality remains consistent with the previous example. The key differences are:

  • Using the BrowserProvider instance for reading/writing data.
  • Manually activating the wallet.
  • Handling wallet events on our own.

Complete code is as follows:

import { useCallback, useEffect, useMemo, useState } from 'react'
import { BrowserProvider, formatUnits, parseUnits, Contract } from 'ethers'
import rubyOneProvider from './sdk'
import ERC20 from './ERC20.json'

const RBT = '0xffFDFC767016f7a3Baa9895D70f895302f82Cfe9'
const DEAD = '0x000000000000000000000000000000000000dEaD'

export default function useWallet() {
const [account, setAccount] = useState('')
const [chainId, setChainId] = useState('')
const [ethBalance, setEthBalance] = useState(0)
const [rbtBalance, setRbtBalance] = useState(0)

const provider = useMemo(() => {
return new BrowserProvider(rubyOneProvider)
}, [])

const getData = useCallback(async () => {
if (!account) return
const contract = new Contract(RBT, ERC20, provider)
const ethBalance = await provider.getBalance(account)
const rbtBalance = await contract.balanceOf(account)
const ethValue = Number(formatUnits(ethBalance))
const rbtValue = Number(formatUnits(rbtBalance))
setEthBalance(ethValue)
setRbtBalance(rbtValue)
}, [provider, account])

const transferRBT = useCallback(async () => {
if (!account) return
const signer = await provider.getSigner()
const contract = new Contract(RBT, ERC20, signer)
const value = parseUnits('10')
const trans = await contract.transfer(DEAD, value)
await trans.wait(1)
getData()
return trans.hash
}, [provider, account, getData])

const init = useCallback(async () =>{
rubyOneProvider.on('accountsChanged', (accounts: string[]) => {
setAccount(accounts[0] || '')
})
rubyOneProvider.on('chainChanged', (chainId: string) => {
setChainId(chainId)
})
rubyOneProvider.on('disconnect', () => {
setAccount('')
})
const network = await provider.getNetwork()
const accounts = await rubyOneProvider.request({
method: 'eth_accounts',
params: []
})
setChainId(network.chainId.toString())
setAccount(accounts[0] || '')
}, [provider])

const connect = useCallback(async () => {
const accounts = await rubyOneProvider.request({
method: 'eth_requestAccounts',
params: []
})
setAccount(accounts[0] || '')
}, [])

useEffect(() => {
getData()
}, [getData])

useEffect(() => {
init()
}, [init])

return {
chainId,
account,
ethBalance,
rbtBalance,
provider,
connect,
getData,
transferRBT
}
}

Write the Component

For component code, you can refer to the example in the previous article.

caution

Be sure not to forget to include the CSS style files required by the SDK into the page.

import '@rubyone/jssdk/dist/style.css'

Conclusion

As illustrated by the example above, even if you're directly utilizing the raw ethers to connect to Ruby One, it's incredibly straightforward. You can easily transfer your MetaMask development experience over.