Skip to content

Instantly share code, notes, and snippets.

@arilotter
Created September 28, 2022 16:36
Show Gist options
  • Save arilotter/025a32193448fc3c42843061267ee85a to your computer and use it in GitHub Desktop.
Save arilotter/025a32193448fc3c42843061267ee85a to your computer and use it in GitHub Desktop.
Sequence Rainbowkit Connector

Make sure you have the newest Sequence.js, at least "0xsequence": "^0.41.2", in your package.json. Put wallet.ts, connector.ts, and logo.ts in a folder called sequence.

import {
ConnectButton,
connectorsForWallets,
RainbowKitProvider,
wallet,
} from '@rainbow-me/rainbowkit';
import { WagmiConfig } from 'wagmi';
import { chain, configureChains, createClient } from 'wagmi';
import { alchemyProvider } from 'wagmi/providers/alchemy';
import "@rainbow-me/rainbowkit/styles.css";
import { sequenceWallet } from './sequence/wallet';
const defaultProvider = alchemyProvider({
apiKey: process.env.ALCHEMY_APIKEY,
});
export const { chains, provider, webSocketProvider } = configureChains(
[chain.polygonMumbai],
[defaultProvider],
);
const connectors = connectorsForWallets([
{
groupName: 'Recommended',
wallets: [
sequenceWallet({ chains }),
wallet.metaMask({ chains }),
wallet.rainbow({ chains }),
wallet.walletConnect({ chains }),
],
},
]);
const wagmiClient = createClient({
autoConnect: true,
connectors: () => [...connectors()],
provider,
webSocketProvider,
});
export default () => {
return (
<WagmiConfig client={wagmiClient}>
<RainbowKitProvider chains={chains}>
<ConnectButton />
</RainbowKitProvider>
</WagmiConfig>
);
};
// build by Ari Lotter
import { sequence } from '0xsequence'
import { mainnetNetworks, testnetNetworks } from '@0xsequence/network'
import type { ConnectOptions, ProviderConfig, Web3Provider } from '@0xsequence/provider'
import { Wallet } from '@0xsequence/provider'
import { Chain } from '@rainbow-me/rainbowkit'
import { Connector, ConnectorData, ConnectorNotFoundError, UserRejectedRequestError } from 'wagmi'
interface Options {
provider?: Partial<ProviderConfig>
connect?: ConnectOptions
shimDisconnect?: boolean
}
let initialized = false
export class SequenceConnector extends Connector<Web3Provider, Options | undefined> {
id = 'sequence'
name = 'Sequence'
// chains = chainConfigList
ready = true
provider: Web3Provider | null = null
wallet: Wallet
connected = false
constructor({ chains, options }: { chains?: Chain[]; options?: Options }) {
super({ chains, options })
if (!initialized) {
initialized = true
sequence.initWallet(chains?.[0]?.id ?? 'polygon')
this.wallet = sequence.getWallet()
}
}
async connect(): Promise<Required<ConnectorData<Web3Provider>>> {
if (!this.wallet.isConnected()) {
this.emit('message', { type: 'connecting' })
const e = await this.wallet.connect(this.options?.connect)
if (e.error) {
throw new UserRejectedRequestError(e.error)
}
if (!e.connected) {
throw new UserRejectedRequestError('Wallet connection rejected')
}
}
console.log('connect')
const chainId = await this.getChainId()
const provider = await this.getProvider()
const account = await this.getAccount()
// provider.on("accountsChanged", this.onAccountsChanged);
this.wallet.on('chainChanged', this.onChainChanged)
provider.on('disconnect', this.onDisconnect)
this.connected = true
return {
account,
chain: {
id: chainId,
unsupported: this.isChainUnsupported(chainId)
},
provider
}
}
async disconnect() {
this.wallet.disconnect()
}
getAccount() {
return this.wallet.getAddress()
}
getChainId() {
// in mobile, when connecting with sequence Rainbowkit first tried to get ChainID for some reason, but in sequence you can't get ChainID before being connected, so forcing here to connect if you want to get ChainID
if (!this.wallet.isConnected()) {
return this.connect().then(() => this.wallet.getChainId())
}
return this.wallet.getChainId()
}
async getProvider() {
if (!this.provider) {
const provider = this.wallet.getProvider()
if (!provider) {
throw new ConnectorNotFoundError('Failed to get Sequence Wallet provider.')
}
this.provider = provider
}
return this.provider
}
async getSigner() {
return this.wallet.getSigner()
}
async isAuthorized() {
try {
const account = await this.getAccount()
return !!account
} catch {
return false
}
}
async switchChain(chainId: number): Promise<Chain> {
await this.provider?.send('wallet_switchEthereumChain', [{ chainId: chainId }])
return { id: chainId } as Chain
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected onAccountsChanged = (accounts: string[]) => {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected onChainChanged = (chain: number | string) => {
this.provider?.emit('chainChanged', chain)
const id = normalizeChainId(chain)
const unsupported = this.isChainUnsupported(id)
this.emit('change', { chain: { id, unsupported } })
}
protected onDisconnect = () => {
this.emit('disconnect')
}
isChainUnsupported(chainId: number): boolean {
return !(mainnetNetworks.some(c => c.chainId === chainId) || testnetNetworks.some(c => c.chainId === chainId))
}
}
function normalizeChainId(chainId: string | number | bigint) {
if (typeof chainId === 'string') return Number.parseInt(chainId, chainId.trim().substring(0, 2) === '0x' ? 16 : 10)
if (typeof chainId === 'bigint') return Number(chainId)
return chainId
}
export const sequenceLogo =
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAzOTYgMzE4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzVfMTMxKSI+DQo8ZyBjbGlwLXBhdGg9InVybCgjY2xpcDFfNV8xMzEpIj4NCjxwYXRoIGQ9Ik0wIDY3LjUwNDlMMCAyNTAuMTY1QzAgMjg3LjQ0NyAzMC4xNDAyIDMxNy42NyA2Ny4zMiAzMTcuNjdIMzI4LjY4QzM2NS44NiAzMTcuNjcgMzk2IDI4Ny40NDcgMzk2IDI1MC4xNjVWNjcuNTA0OUMzOTYgMzAuMjIzIDM2NS44NiAwIDMyOC42OCAwSDY3LjMyQzMwLjE0MDIgMCAwIDMwLjIyMyAwIDY3LjUwNDlaIiBmaWxsPSIjMTExMTExIi8+DQo8cGF0aCBkPSJNMCA2Ny41MDQ5TDAgMjUwLjE2NUMwIDI4Ny40NDcgMzAuMTQwMiAzMTcuNjcgNjcuMzIgMzE3LjY3SDMyOC42OEMzNjUuODYgMzE3LjY3IDM5NiAyODcuNDQ3IDM5NiAyNTAuMTY1VjY3LjUwNDlDMzk2IDMwLjIyMyAzNjUuODYgMCAzMjguNjggMEg2Ny4zMkMzMC4xNDAyIDAgMCAzMC4yMjMgMCA2Ny41MDQ5WiIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzVfMTMxKSIvPg0KPHBhdGggZD0iTTk4Ljk5OTkgNzkuNDE3NkM5OC45OTk5IDY4LjQ1MjMgOTAuMTM1MSA1OS41NjMyIDc5LjE5OTkgNTkuNTYzMkM2OC4yNjQ3IDU5LjU2MzIgNTkuMzk5OSA2OC40NTIzIDU5LjM5OTkgNzkuNDE3NkM1OS4zOTk5IDkwLjM4MjggNjguMjY0NyA5OS4yNzIgNzkuMTk5OSA5OS4yNzJDOTAuMTM1MSA5OS4yNzIgOTguOTk5OSA5MC4zODI4IDk4Ljk5OTkgNzkuNDE3NloiIGZpbGw9InVybCgjcGFpbnQxX2xpbmVhcl81XzEzMSkiLz4NCjxwYXRoIGQ9Ik05OC45OTk5IDc5LjQxNzZDOTguOTk5OSA2OC40NTIzIDkwLjEzNTEgNTkuNTYzMiA3OS4xOTk5IDU5LjU2MzJDNjguMjY0NyA1OS41NjMyIDU5LjM5OTkgNjguNDUyMyA1OS4zOTk5IDc5LjQxNzZDNTkuMzk5OSA5MC4zODI4IDY4LjI2NDcgOTkuMjcyIDc5LjE5OTkgOTkuMjcyQzkwLjEzNTEgOTkuMjcyIDk4Ljk5OTkgOTAuMzgyOCA5OC45OTk5IDc5LjQxNzZaIiBmaWxsPSJ1cmwoI3BhaW50Ml9saW5lYXJfNV8xMzEpIi8+DQo8cGF0aCBkPSJNOTguOTk5OSA3OS40MTc2Qzk4Ljk5OTkgNjguNDUyMyA5MC4xMzUxIDU5LjU2MzIgNzkuMTk5OSA1OS41NjMyQzY4LjI2NDcgNTkuNTYzMiA1OS4zOTk5IDY4LjQ1MjMgNTkuMzk5OSA3OS40MTc2QzU5LjM5OTkgOTAuMzgyOCA2OC4yNjQ3IDk5LjI3MiA3OS4xOTk5IDk5LjI3MkM5MC4xMzUxIDk5LjI3MiA5OC45OTk5IDkwLjM4MjggOTguOTk5OSA3OS40MTc2WiIgZmlsbD0idXJsKCNwYWludDNfbGluZWFyXzVfMTMxKSIvPg0KPHBhdGggZD0iTTk4Ljk5OTkgMjM4LjEyNkM5OC45OTk5IDIyNy4xNjEgOTAuMTM1MSAyMTguMjcyIDc5LjE5OTkgMjE4LjI3MkM2OC4yNjQ3IDIxOC4yNzIgNTkuMzk5OSAyMjcuMTYxIDU5LjM5OTkgMjM4LjEyNkM1OS4zOTk5IDI0OS4wOTIgNjguMjY0NyAyNTcuOTgxIDc5LjE5OTkgMjU3Ljk4MUM5MC4xMzUxIDI1Ny45ODEgOTguOTk5OSAyNDkuMDkyIDk4Ljk5OTkgMjM4LjEyNloiIGZpbGw9InVybCgjcGFpbnQ0X2xpbmVhcl81XzEzMSkiLz4NCjxwYXRoIGQ9Ik0zMzYuNiAxNTguODM1QzMzNi42IDE0Ny44NyAzMjcuNzM1IDEzOC45ODEgMzE2LjggMTM4Ljk4MUMzMDUuODY1IDEzOC45ODEgMjk3IDE0Ny44NyAyOTcgMTU4LjgzNUMyOTcgMTY5LjggMzA1Ljg2NSAxNzguNjkgMzE2LjggMTc4LjY5QzMyNy43MzUgMTc4LjY5IDMzNi42IDE2OS44IDMzNi42IDE1OC44MzVaIiBmaWxsPSJ1cmwoI3BhaW50NV9saW5lYXJfNV8xMzEpIi8+DQo8cGF0aCBkPSJNMzM2LjYgMTU4LjgzNUMzMzYuNiAxNDcuODcgMzI3LjczNSAxMzguOTgxIDMxNi44IDEzOC45ODFDMzA1Ljg2NSAxMzguOTgxIDI5NyAxNDcuODcgMjk3IDE1OC44MzVDMjk3IDE2OS44IDMwNS44NjUgMTc4LjY5IDMxNi44IDE3OC42OUMzMjcuNzM1IDE3OC42OSAzMzYuNiAxNjkuOCAzMzYuNiAxNTguODM1WiIgZmlsbD0idXJsKCNwYWludDZfbGluZWFyXzVfMTMxKSIvPg0KPHBhdGggZD0iTTMxNi44IDU5LjU2MzJIMTU4LjRDMTQ3LjQ2NSA1OS41NjMyIDEzOC42IDY4LjQ1MjMgMTM4LjYgNzkuNDE3NkMxMzguNiA5MC4zODI4IDE0Ny40NjUgOTkuMjcyIDE1OC40IDk5LjI3MkgzMTYuOEMzMjcuNzM1IDk5LjI3MiAzMzYuNiA5MC4zODI4IDMzNi42IDc5LjQxNzZDMzM2LjYgNjguNDUyMyAzMjcuNzM1IDU5LjU2MzIgMzE2LjggNTkuNTYzMloiIGZpbGw9InVybCgjcGFpbnQ3X2xpbmVhcl81XzEzMSkiLz4NCjxwYXRoIGQ9Ik0zMTYuOCAyMTguMjcySDE1OC40QzE0Ny40NjUgMjE4LjI3MiAxMzguNiAyMjcuMTYxIDEzOC42IDIzOC4xMjZDMTM4LjYgMjQ5LjA5MiAxNDcuNDY1IDI1Ny45ODEgMTU4LjQgMjU3Ljk4MUgzMTYuOEMzMjcuNzM1IDI1Ny45ODEgMzM2LjYgMjQ5LjA5MiAzMzYuNiAyMzguMTI2QzMzNi42IDIyNy4xNjEgMzI3LjczNSAyMTguMjcyIDMxNi44IDIxOC4yNzJaIiBmaWxsPSJ1cmwoI3BhaW50OF9saW5lYXJfNV8xMzEpIi8+DQo8cGF0aCBkPSJNMjM3LjYgMTM4Ljk4MUg3OS4yQzY4LjI2NDggMTM4Ljk4MSA1OS40IDE0Ny44NyA1OS40IDE1OC44MzVDNTkuNCAxNjkuOCA2OC4yNjQ4IDE3OC42OSA3OS4yIDE3OC42OUgyMzcuNkMyNDguNTM1IDE3OC42OSAyNTcuNCAxNjkuOCAyNTcuNCAxNTguODM1QzI1Ny40IDE0Ny44NyAyNDguNTM1IDEzOC45ODEgMjM3LjYgMTM4Ljk4MVoiIGZpbGw9InVybCgjcGFpbnQ5X2xpbmVhcl81XzEzMSkiLz4NCjwvZz4NCjwvZz4NCjxkZWZzPg0KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzVfMTMxIiB4MT0iMTk4IiB5MT0iNC4wNTg1NGUtMDUiIHgyPSIxOTgiIHkyPSIzMTgiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4NCjxzdG9wIHN0b3AtY29sb3I9IiMxRDI3M0QiLz4NCjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzBEMEYxMyIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQxX2xpbmVhcl81XzEzMSIgeDE9IjY1LjUiIHkxPSI5OSIgeDI9IjkyLjUiIHkyPSI2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPg0KPHN0b3Agc3RvcC1jb2xvcj0iIzQ0NjJGRSIvPg0KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjN0Q2OUZBIi8+DQo8L2xpbmVhckdyYWRpZW50Pg0KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDJfbGluZWFyXzVfMTMxIiB4MT0iNjIuODc5OSIgeTE9Ijk5LjI5MTIiIHgyPSI5Ni4xMzc3IiB5Mj0iOTcuNTkxMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPg0KPHN0b3Agc3RvcC1jb2xvcj0iIzM3NTdGRCIvPg0KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNjk4MEZBIi8+DQo8L2xpbmVhckdyYWRpZW50Pg0KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDNfbGluZWFyXzVfMTMxIiB4MT0iNjIuODc5OSIgeTE9Ijk5LjI5MTIiIHgyPSI5Ni4xMzc3IiB5Mj0iOTcuNTkxMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPg0KPHN0b3Agc3RvcC1jb2xvcj0iIzI0NDdGRiIvPg0KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNjk4MEZBIi8+DQo8L2xpbmVhckdyYWRpZW50Pg0KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDRfbGluZWFyXzVfMTMxIiB4MT0iNjUiIHkxPSIyNTEuNSIgeDI9IjkxLjUiIHkyPSIyMjMuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPg0KPHN0b3Agc3RvcC1jb2xvcj0iI0JDM0VFNiIvPg0KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjRDk3MkYxIi8+DQo8L2xpbmVhckdyYWRpZW50Pg0KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDVfbGluZWFyXzVfMTMxIiB4MT0iMzA1IiB5MT0iMTcyIiB4Mj0iMzI5LjUiIHkyPSIxNDYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4NCjxzdG9wIHN0b3AtY29sb3I9IiMyOUJERkYiLz4NCjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzk2RTdGQiIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQ2X2xpbmVhcl81XzEzMSIgeDE9IjMwMC4xOCIgeTE9IjE3OC40MTgiIHgyPSIzMzQuNTY3IiB5Mj0iMTc2Ljc3MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPg0KPHN0b3Agc3RvcC1jb2xvcj0iIzIzQkJGRiIvPg0KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjODVFN0ZGIi8+DQo8L2xpbmVhckdyYWRpZW50Pg0KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDdfbGluZWFyXzVfMTMxIiB4MT0iMTU0LjUiIHkxPSI5OSIgeDI9IjMxNy41IiB5Mj0iNjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4NCjxzdG9wIHN0b3AtY29sb3I9IiMyM0JCRkYiLz4NCjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzg1RTdGRiIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQ4X2xpbmVhcl81XzEzMSIgeDE9IjE1NiIgeTE9IjI1OCIgeDI9IjMxMi41IiB5Mj0iMjE4IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+DQo8c3RvcCBzdG9wLWNvbG9yPSIjMjQ0N0ZGIi8+DQo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM2OTgwRkEiLz4NCjwvbGluZWFyR3JhZGllbnQ+DQo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50OV9saW5lYXJfNV8xMzEiIHgxPSI4Ni4wMDAxIiB5MT0iMTc5IiB4Mj0iMjM1LjUiIHkyPSIxMzkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4NCjxzdG9wIHN0b3AtY29sb3I9IiM2NjM0RkYiLz4NCjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzlDNkRGRiIvPg0KPC9saW5lYXJHcmFkaWVudD4NCjxjbGlwUGF0aCBpZD0iY2xpcDBfNV8xMzEiPg0KPHJlY3Qgd2lkdGg9IjM5NiIgaGVpZ2h0PSIzMTcuNjciIGZpbGw9IndoaXRlIi8+DQo8L2NsaXBQYXRoPg0KPGNsaXBQYXRoIGlkPSJjbGlwMV81XzEzMSI+DQo8cmVjdCB3aWR0aD0iMzk2IiBoZWlnaHQ9IjMxNy42NyIgZmlsbD0id2hpdGUiLz4NCjwvY2xpcFBhdGg+DQo8L2RlZnM+DQo8L3N2Zz4='
import { Chain, Wallet } from '@rainbow-me/rainbowkit'
import { SequenceConnector } from './connector'
import { sequenceLogo } from './logo'
export interface MyWalletOptions {
chains: Chain[]
shimDisconnect?: boolean | undefined
}
export const sequenceWallet = ({ chains, shimDisconnect }: MyWalletOptions): Wallet => ({
id: 'sequence',
name: 'Sequence',
iconUrl: sequenceLogo,
iconBackground: '#fff',
downloadUrls: {
// browserExtension: 'https://chrome.google.com/webstore/detail/sequence-wallet/ocmccklecaalljlflmclidjeclpcpdim'
// android:
// ios:
browserExtension: 'https://sequence.app' // default to the web app for now
},
createConnector: () => {
const connector = new SequenceConnector({
chains,
options: {
shimDisconnect,
connect: {
app: 'DappName',
authorize: false
}
}
})
return {
connector,
mobile: {
getUri: async () => {
try {
await connector.connect()
return window.location.href
} catch (e) {
console.error('Failed to connect', e)
}
return ''
}
},
desktop: {
getUri: async () => {
try {
await connector.connect()
} catch (e) {
console.error('Failed to connect', e)
}
return ''
}
}
}
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment