web3-react-okx-connector
Version:
Okx wallet injected provider connector for web3-react@v6
249 lines (216 loc) • 6.74 kB
text/typescript
import { AbstractConnectorArguments, ConnectorUpdate } from "@web3-react/types";
import { AbstractConnector } from "@web3-react/abstract-connector";
import warning from "tiny-warning";
export type SendReturnResult = { result: any };
export type SendReturn = any;
export type Send = (
method: string,
params?: any[]
) => Promise<SendReturnResult | SendReturn>;
export type SendOld = ({
method,
}: {
method: string;
}) => Promise<SendReturnResult | SendReturn>;
const __DEV__ = process.env.NODE_ENV !== "development" ? false : true;
function parseSendReturn(sendReturn: SendReturnResult | SendReturn): any {
return sendReturn.hasOwnProperty("result") ? sendReturn.result : sendReturn;
}
export class NoOkxwalletProviderError extends Error {
public constructor() {
super();
this.name = this.constructor.name;
this.message = "No okxwallet provider was found on window.okxwallet.";
}
}
export class UserRejectedRequestError extends Error {
public constructor() {
super();
this.name = this.constructor.name;
this.message = "The user rejected the request.";
}
}
export class OkxConnector extends AbstractConnector {
constructor(kwargs: AbstractConnectorArguments) {
super(kwargs);
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);
}
window.location.reload();
this.emitUpdate({ chainId, provider: window.okxwallet });
}
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();
}
// if user never connected
public async activate(): Promise<ConnectorUpdate> {
if (!window.okxwallet) {
throw new NoOkxwalletProviderError();
}
if (window.okxwallet.on) {
window.okxwallet.on("chainChanged", this.handleChainChanged);
window.okxwallet.on("accountsChanged", this.handleAccountsChanged);
window.okxwallet.on("close", this.handleClose);
}
if ((window.okxwallet as any).isMetaMask) {
(window.okxwallet as any).autoRefreshOnNetworkChange = false;
}
// try to activate + get account via eth_requestAccounts
let account;
try {
account = await (window.okxwallet.send as Send)(
"eth_requestAccounts"
).then((sendReturn) => parseSendReturn(sendReturn)[0]);
} catch (error) {
if ((error as any).code === 4001) {
throw new UserRejectedRequestError();
}
warning(
false,
"eth_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.okxwallet
.enable()
.then((sendReturn) => sendReturn && parseSendReturn(sendReturn)[0]);
}
return { provider: window.okxwallet, ...(account ? { account } : {}) };
}
public async getProvider(): Promise<any> {
return window.okxwallet;
}
public async getChainId(): Promise<number | string> {
if (!window.okxwallet) {
throw new NoOkxwalletProviderError();
}
let chainId;
try {
chainId = await (window.okxwallet.send as Send)("eth_chainId").then(
parseSendReturn
);
} catch {
warning(
false,
"eth_chainId was unsuccessful, falling back to net_version"
);
}
if (!chainId) {
try {
chainId = await (window.okxwallet.send as Send)("net_version").then(
parseSendReturn
);
} catch {
warning(
false,
"net_version was unsuccessful, falling back to net version v2"
);
}
}
if (!chainId) {
try {
chainId = parseSendReturn(
(window.okxwallet.send as SendOld)({ method: "net_version" })
);
} catch {
warning(
false,
"net_version v2 was unsuccessful, falling back to manual matches and static properties"
);
}
}
if (!chainId) {
if ((window.okxwallet as any).isDapper) {
chainId = parseSendReturn(
(window.okxwallet as any).cachedResults.net_version
);
} else {
chainId =
(window.okxwallet as any).chainId ||
(window.okxwallet as any).netVersion ||
(window.okxwallet as any).networkVersion ||
(window.okxwallet as any)._chainId;
}
}
return chainId;
}
public async getAccount(): Promise<null | string> {
if (!window.okxwallet) {
throw new NoOkxwalletProviderError();
}
let account;
try {
account = await (window.okxwallet.send as Send)("eth_accounts").then(
(sendReturn) => parseSendReturn(sendReturn)[0]
);
} catch {
warning(false, "eth_accounts was unsuccessful, falling back to enable");
}
if (!account) {
try {
account = await window.okxwallet
.enable()
.then((sendReturn) => parseSendReturn(sendReturn)[0]);
} catch {
warning(
false,
"enable was unsuccessful, falling back to eth_accounts v2"
);
}
}
if (!account) {
account = parseSendReturn(
(window.okxwallet.send as SendOld)({ method: "eth_accounts" })
)[0];
}
return account;
}
public deactivate() {
if (window.okxwallet && window.okxwallet.removeListener) {
window.okxwallet.removeListener("chainChanged", this.handleChainChanged);
window.okxwallet.removeListener(
"accountsChanged",
this.handleAccountsChanged
);
window.okxwallet.removeListener("close", this.handleClose);
}
}
public async isAuthorized(): Promise<boolean> {
if (!window.okxwallet) {
return false;
}
try {
return await (window.okxwallet.send as Send)("eth_accounts").then(
(sendReturn) => {
if (parseSendReturn(sendReturn).length > 0) {
return true;
} else {
return false;
}
}
);
} catch {
return false;
}
}
}