exalias
Version:
A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps
177 lines (148 loc) • 5.47 kB
text/typescript
import { AbstractConnectorArguments, ConnectorUpdate } from '@web3-react/types'
import { AbstractConnector } from '@web3-react/abstract-connector'
import warning from 'tiny-warning'
import { SendReturnResult, SendReturn, Send, SendOld } from './types'
function parseSendReturn(sendReturn: SendReturnResult | SendReturn): any {
return sendReturn.hasOwnProperty('result') ? sendReturn.result : sendReturn
}
export class NoStarcoinProviderError extends Error {
public constructor() {
super()
this.name = this.constructor.name
this.message = 'No Starcoin provider was found on window.obstarcoin.'
}
}
export class UserRejectedRequestError extends Error {
public constructor() {
super()
this.name = this.constructor.name
this.message = 'The user rejected the request.'
}
}
export class OpenBlockConnector extends AbstractConnector {
constructor(kwargs: AbstractConnectorArguments) {
super(kwargs)
this.handleNetworkChanged = this.handleNetworkChanged.bind(this)
this.handleChainChanged = this.handleChainChanged.bind(this)
this.handleAccountsChanged = this.handleAccountsChanged.bind(this)
this.handleClose = this.handleClose.bind(this)
}
private handleChainChanged(chainId: string | number): void {
if (__DEV__) {
console.log("Handling 'chainChanged' event with payload", chainId)
}
this.emitUpdate({ chainId, provider: window.obstarcoin })
}
private handleAccountsChanged(accounts: string[]): void {
if (__DEV__) {
console.log("Handling 'accountsChanged' event with payload", accounts)
}
if (accounts.length === 0) {
this.emitDeactivate()
} else {
this.emitUpdate({ account: accounts[0] })
}
}
private handleClose(code: number, reason: string): void {
if (__DEV__) {
console.log("Handling 'close' event with payload", code, reason)
}
this.emitDeactivate()
}
private handleNetworkChanged(networkId: string | number): void {
if (__DEV__) {
console.log("Handling 'networkChanged' event with payload", networkId)
}
this.emitUpdate({ chainId: networkId, provider: window.obstarcoin })
}
public async activate(): Promise<ConnectorUpdate> {
if (!window.obstarcoin) {
throw new NoStarcoinProviderError()
}
if (window.obstarcoin.on) {
window.obstarcoin.on('chainChanged', this.handleChainChanged)
window.obstarcoin.on('accountsChanged', this.handleAccountsChanged)
window.obstarcoin.on('close', this.handleClose)
window.obstarcoin.on('networkChanged', this.handleNetworkChanged)
}
if ((window.obstarcoin as any).isStarMask) {
; (window.obstarcoin as any).autoRefreshOnNetworkChange = false
}
// try to activate + get account via stc_requestAccounts
let account
try {
account = await (window.obstarcoin.send as Send)('stc_requestAccounts').then(
sendReturn => parseSendReturn(sendReturn)[0]
)
} catch (error) {
if ((error as any).code === 4001) {
throw new UserRejectedRequestError()
}
warning(false, 'stc_requestAccounts was unsuccessful, falling back to enable')
}
// if unsuccessful, try enable
if (!account) {
// if enable is successful but doesn't return accounts, fall back to getAccount (not happy i have to do this...)
account = await window.obstarcoin.enable().then(sendReturn => sendReturn && parseSendReturn(sendReturn)[0])
}
return { provider: window.obstarcoin, ...(account ? { account } : {}) }
}
public async getProvider(): Promise<any> {
return window.obstarcoin
}
public async getChainId(): Promise<number | string> {
if (!window.obstarcoin) {
throw new NoStarcoinProviderError()
}
const chainId =
(window.obstarcoin as any).chainId ||
(window.obstarcoin as any).networkVersion
return chainId
}
public async getAccount(): Promise<null | string> {
if (!window.obstarcoin) {
throw new NoStarcoinProviderError()
}
let account
try {
account = await (window.obstarcoin.send as Send)('stc_accounts').then(sendReturn => parseSendReturn(sendReturn)[0])
} catch {
warning(false, 'stc_accounts was unsuccessful, falling back to enable')
}
if (!account) {
try {
account = await window.obstarcoin.enable().then(sendReturn => parseSendReturn(sendReturn)[0])
} catch {
warning(false, 'enable was unsuccessful, falling back to stc_accounts v2')
}
}
if (!account) {
account = parseSendReturn((window.obstarcoin.send as SendOld)({ method: 'stc_accounts' }))[0]
}
return account
}
public deactivate() {
if (window.obstarcoin && window.obstarcoin.removeListener) {
window.obstarcoin.removeListener('chainChanged', this.handleChainChanged)
window.obstarcoin.removeListener('accountsChanged', this.handleAccountsChanged)
window.obstarcoin.removeListener('close', this.handleClose)
window.obstarcoin.removeListener('networkChanged', this.handleNetworkChanged)
}
}
public async isAuthorized(): Promise<boolean> {
if (!window.obstarcoin) {
return false
}
try {
return await (window.obstarcoin.send as Send)('stc_accounts').then(sendReturn => {
if (parseSendReturn(sendReturn).length > 0) {
return true
} else {
return false
}
})
} catch {
return false
}
}
}