-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce provider details in base
- Loading branch information
Showing
23 changed files
with
459 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,100 @@ | ||
import generateId from '../helpers/generateId' | ||
import LocalStorage from '../helpers/localStorage' | ||
import { parseChainId, validateChainId } from '../helpers/chainId' | ||
import { ConnectResult, Ethereumish, IProvider, ProviderRpcError, ProviderState, ProviderType } from '../types' | ||
import { Connector } from './Connector' | ||
import { ensureChainIdAllowed, parseChainId, validateChainId } from '../helpers/chainId' | ||
|
||
export abstract class BaseProvider implements IProvider { | ||
export abstract class AbstractProviderBase<T> implements IProvider { | ||
public id: string | ||
public name: string | ||
public logo: string | ||
public type: ProviderType | ||
private localStorage!: LocalStorage | ||
private options!: ConnectorOptions | ||
public provider!: Ethereumish | null | ||
public options!: T | ||
public address!: string | null | ||
public state!: ProviderState | null | ||
public chainId!: number | null | ||
public error!: Error | null | ||
|
||
static CACHED_PROVIDER_KEY = 'CACHED_PROVIDER' | ||
public _initialized: boolean | ||
|
||
protected constructor(name: string, logo: string, type: ProviderType) { | ||
private connector!: Connector | ||
|
||
protected constructor(name: string, logo: string, type: ProviderType, options: T) { | ||
this.id = generateId(name) | ||
this.name = name | ||
this.logo = logo | ||
this.type = type | ||
this.options = options | ||
this._initialized = false | ||
} | ||
|
||
init(options: ConnectorOptions, localStorage: LocalStorage) { | ||
this.options = options | ||
this.localStorage = localStorage | ||
return this | ||
_init(connector: Connector) { | ||
this.connector = connector | ||
this._initialized = true | ||
} | ||
|
||
protected abstract _connect(): ConnectResult | ||
|
||
async connect(): ConnectResult { | ||
if (!this._initialized) { | ||
throw new Error('Provider not initialized') | ||
} | ||
this.state = ProviderState.LOADING | ||
this.provider = (await this._connect()) as Ethereumish | ||
this.activate() | ||
return this.provider | ||
} | ||
|
||
disconnect(): void { | ||
this.deactivate() | ||
} | ||
|
||
activate() { | ||
this.address = 'address' | ||
this.chainId = 1 | ||
this.error = null | ||
this.connector.provider = this | ||
this.state = this.error ? ProviderState.ERROR : ProviderState.CONNECTED | ||
this.addListener() | ||
} | ||
|
||
protected abstract onConnect(options: ConnectorOptions): ConnectResult | ||
deactivate() { | ||
this.address = null | ||
this.state = null | ||
this.chainId = null | ||
this.error = null | ||
this.connector.provider = null | ||
} | ||
|
||
addListener() { | ||
this.provider?.on('disconnect', this.onDisconnect) | ||
this.provider?.on('chainChanged', this.onChainChanged) | ||
this.provider?.on('accountsChanged', this.onAccountsChanged) | ||
} | ||
|
||
onDisconnect(error: ProviderRpcError | undefined) { | ||
this.deactivate() | ||
this.reportError(error) | ||
} | ||
|
||
onChainChanged(chainId: number | string) { | ||
const newChainId = parseChainId(chainId) | ||
this.reportError(validateChainId(newChainId)) | ||
const { allowedChainIds } = this.connector.options | ||
if (allowedChainIds) { | ||
this.reportError(ensureChainIdAllowed(newChainId, allowedChainIds)) | ||
} | ||
this.chainId = newChainId | ||
} | ||
|
||
onAccountsChanged(accounts: string[]) { | ||
this.address = Array.isArray(accounts) ? accounts[0] : '' | ||
} | ||
|
||
async connect() { | ||
if (!this.options) { | ||
return null | ||
reportError(error?: Error) { | ||
if (error) { | ||
this.error = error | ||
this.state = ProviderState.ERROR | ||
} | ||
const provider = await this.onConnect(this.options) | ||
const chainId = parseChainId(provider.chainId) | ||
validateChainId(chainId, this.options.chainId || 1) | ||
this.localStorage.set(BaseProvider.CACHED_PROVIDER_KEY, this.id) | ||
return provider | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { ConnectorOptions, IProvider } from '../types' | ||
import LocalStorage from '../helpers/localStorage' | ||
|
||
export class Connector { | ||
public options: ConnectorOptions | ||
public provider!: IProvider | null | ||
private readonly _providers: IProvider[] | ||
|
||
constructor(options: ConnectorOptions, providers: IProvider[]) { | ||
this.options = options | ||
this._providers = providers | ||
} | ||
|
||
static async init(options: ConnectorOptions, providers: IProvider[]): Promise<Connector> { | ||
const connector = new Connector(options, providers) | ||
connector._providers.forEach((p) => p._init(connector)) | ||
connector.provider = await connector.loadProviderCache(providers) | ||
return connector | ||
} | ||
|
||
async loadProviderCache(providers: IProvider[]) { | ||
let cachedProvider = null | ||
const localStorage = new LocalStorage(this.options.cache.key) | ||
const providerId = localStorage.get() | ||
if (providerId) { | ||
const providerById = providers.find((p) => p.id === providerId) | ||
if (providerById) { | ||
cachedProvider = await providerById.connect() | ||
} | ||
} | ||
return cachedProvider | ||
} | ||
|
||
listProviders() { | ||
return this._providers | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,8 @@ | ||
import { BaseProvider } from './BaseProvider' | ||
import { AbstractProviderBase } from './BaseProvider' | ||
import { ProviderType } from '../types' | ||
|
||
export class ExternalProvider extends BaseProvider { | ||
protected onConnect!: ConnectFn | ||
|
||
constructor(name: string, logo: string, type: ProviderType, onConnect: ConnectFn) { | ||
super(name, logo, type) | ||
this.onConnect = onConnect | ||
export abstract class AbstractExternalProvider<T = Record<string, unknown>> extends AbstractProviderBase<T> { | ||
protected constructor(name: string, logo: string, type: ProviderType, options: T = {} as T) { | ||
super(name, logo, type, options) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,5 @@ | ||
import { Connector } from './connector' | ||
import { BaseProvider } from './BaseProvider' | ||
import { ExternalProvider } from './ExternalProvider' | ||
import { InjectedProvider } from './InjectedProvider' | ||
import { Connector } from './Connector' | ||
|
||
export default { | ||
Connector, | ||
BaseProvider, | ||
ExternalProvider, | ||
InjectedProvider, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export class ProviderNotInitializedError extends Error { | ||
public constructor() { | ||
super(`Provider not initialized`) | ||
this.name = ProviderNotInitializedError.name | ||
Object.setPrototypeOf(this, ProviderNotInitializedError.prototype) | ||
} | ||
} | ||
|
||
export class ChainIdNotAllowedError extends Error { | ||
public readonly chainId: number | ||
|
||
public constructor(chainId: number, allowedChainIds: number[]) { | ||
super(`chainId ${chainId} not included in ${allowedChainIds.toString()}`) | ||
this.chainId = chainId | ||
this.name = ChainIdNotAllowedError.name | ||
Object.setPrototypeOf(this, ChainIdNotAllowedError.prototype) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.