Skip to content

Commit

Permalink
feat: add sequence and web3auth wallets
Browse files Browse the repository at this point in the history
  • Loading branch information
aramalipoor committed Nov 14, 2022
1 parent 1688934 commit 3f6f94b
Show file tree
Hide file tree
Showing 31 changed files with 33,020 additions and 5,440 deletions.
37,272 changes: 31,946 additions & 5,326 deletions packages/common/package-lock.json

Large diffs are not rendered by default.

51 changes: 50 additions & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,22 @@
"build": "rollup -c"
},
"peerDependencies": {
"@0xsequence/wagmi-connector": "*",
"@ethersproject/providers": "*",
"@everipedia/wagmi-magic-connector": "*",
"@gnosis.pm/safe-apps-provider": "*",
"@gnosis.pm/safe-apps-sdk": "*",
"@wagmi/core": "*",
"ethers": "*"
"@web3-onboard/common": "*",
"@web3-onboard/core": "*",
"@web3-onboard/injected-wallets": "*",
"@web3-onboard/ledger": "*",
"@web3-onboard/portis": "*",
"@web3auth/ui": "*",
"@web3auth/web3auth-wagmi-connector": "*",
"ethers": "*",
"bowser": "*",
"eventemitter3": "*"
},
"peerDependenciesMeta": {
"@ethersproject/providers": {
Expand All @@ -41,13 +51,52 @@
},
"ethers": {
"optional": true
},
"bowser": {
"optional": true
},
"eventemitter3": {
"optional": true
},
"@0xsequence/wagmi-connector": {
"optional": true
},
"@web3-onboard/common": {
"optional": true
},
"@web3-onboard/core": {
"optional": true
},
"@web3-onboard/injected-wallets": {
"optional": true
},
"@web3-onboard/ledger": {
"optional": true
},
"@web3-onboard/portis": {
"optional": true
},
"@web3auth/ui": {
"optional": true
},
"@web3auth/web3auth-wagmi-connector": {
"optional": true
}
},
"dependencies": {
"@0xsequence/wagmi-connector": "^1.0.1",
"@everipedia/wagmi-magic-connector": "^0.6.5",
"@gnosis.pm/safe-apps-provider": "^0.13.1",
"@gnosis.pm/safe-apps-sdk": "^7.8.0",
"@wagmi/core": "^0.5.7",
"@web3-onboard/common": "^2.2.3",
"@web3-onboard/core": "^2.10.0",
"@web3-onboard/injected-wallets": "^2.3.0",
"@web3-onboard/ledger": "^2.3.2",
"@web3-onboard/portis": "^2.1.3",
"@web3auth/ui": "^3.0.4",
"@web3auth/web3auth-wagmi-connector": "^1.0.0",
"bowser": "^2.11.0",
"ethers": "^5.6.5"
},
"main": "dist/index.js",
Expand Down
11 changes: 11 additions & 0 deletions packages/common/src/connectors/base/extended-connector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Connector } from '@wagmi/core';

import { CustodyType } from '../../types';

export interface ExtendedConnector extends Connector {
name: string;
available: boolean;
ready: boolean;
custodyType: CustodyType;
icon?: string | ((props: any) => JSX.Element);
}
3 changes: 3 additions & 0 deletions packages/common/src/connectors/base/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './extended-connector';
export * from './onboard-base-connector';
export * from './onboard-injected-base';
202 changes: 202 additions & 0 deletions packages/common/src/connectors/base/onboard-base-connector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import { Web3Provider } from '@ethersproject/providers';
import {
Chain,
Connector,
ConnectorNotFoundError,
ProviderRpcError,
SwitchChainError,
UserRejectedRequestError,
} from '@wagmi/core';
import type { EIP1193Provider, WalletModule } from '@web3-onboard/common';
import { BigNumber, utils } from 'ethers';
import EventEmitter from 'eventemitter3';

import { CustodyType } from '../../types';
import { ExtendedConnector } from './extended-connector';

function normalizeChainId(chainId: string | number) {
if (typeof chainId === 'string') {
const isHex = chainId.trim().substring(0, 2);

return Number.parseInt(chainId, isHex === '0x' ? 16 : 10);
}
return chainId;
}

export type BaseOptions = {
appName: string;
appLogo: string;
};

abstract class Web3OnboardConnectorBase<TOptions extends BaseOptions>
extends Connector<any, TOptions>
implements ExtendedConnector
{
name: string = '';
icon?: ExtendedConnector['icon'];
ready: boolean = false;
available: boolean = true;
custodyType: CustodyType = CustodyType.UNKNOWN;

provider!: EIP1193Provider;

constructor(config: { chains?: Chain[]; options: TOptions }) {
super({ ...config, options: config.options });

this.getWalletModule()
.then((m) => {
if (!this.name) {
this.name = m.label;
}
this.ready = true;
this.available = true;

if (!this.icon) {
m.getIcon().then((icon) => {
this.icon = icon;
});
}
})
.catch((e) => {
this.ready = false;
this.available = false;
this.emit('error', e);
});
}

abstract getWalletModule(): Promise<WalletModule>;

async connect() {
const provider = await this.getProvider();

if (provider?.on) {
provider.on('accountsChanged', this.onAccountsChanged.bind(this));
provider.on('chainChanged', this.onChainChanged.bind(this));
provider.on('disconnect', this.onDisconnect.bind(this));
}

const account = await this.getAccount();
const id = await this.getChainId();

return {
account,
provider,
chain: { id, unsupported: await this.isChainUnsupported(id) },
};
}

async disconnect() {
const provider = await this.getProvider();
if (!provider?.removeListener) return;

provider.removeListener('accountsChanged', this.onAccountsChanged);
provider.removeListener('chainChanged', this.onChainChanged);
provider.removeListener('disconnect', this.onDisconnect);
}

async getAccount() {
const accounts = await (
await this.getProvider()
).request({ method: 'eth_requestAccounts' });

if (!accounts.length) {
throw new Error('No accounts found');
}

return accounts[0].toString();
}

async getChainId() {
if (!this.provider) {
throw new ConnectorNotFoundError();
}

return normalizeChainId(
await this.provider.request({ method: 'eth_chainId' }),
);
}

async getProvider() {
const walletModule = await this.getWalletModule();

if (!this.provider) {
this.provider = (
await walletModule.getInterface({
chains: this.chains.map((x) => ({
id: x.id.toString(),
label: x.name,
rpcUrl: x.rpcUrls.default,
token: x.nativeCurrency?.symbol || 'Token',
})),
BigNumber,
EventEmitter,
appMetadata: {
name: this.options?.appName || 'Flair',
icon: this.options?.appLogo || 'https://wagmi.io/favicon.ico',
},
})
).provider;
}

return this.provider;
}

async getSigner() {
const provider = await this.getProvider();
const account = await this.getAccount();
return new Web3Provider(provider, 'any').getSigner(account);
}

async isAuthorized() {
return false;
}

switchChain: undefined | any = async (chainId: number) => {
const provider = await this.getProvider();
const id = normalizeChainId(chainId);

try {
await provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: id.toString() }],
});
return (
this.chains.find((x) => x.id === chainId) ?? {
id: chainId,
name: `Chain ${id}`,
network: `${id}`,
rpcUrls: { default: '' },
}
);
} catch (error) {
const message =
typeof error === 'string'
? error
: (error as ProviderRpcError)?.message;
if (/user rejected request/i.test(message))
throw new UserRejectedRequestError(error);
throw new SwitchChainError(error);
}
};

protected onAccountsChanged(accounts: string[]) {
if (accounts.length === 0) this.emit('disconnect');
else this.emit('change', { account: utils.getAddress(accounts[0]) });
}

protected isChainUnsupported(chainId: number) {
return !this.chains.some((x) => x.id === chainId);
}

protected onChainChanged(chainId: string | number) {
const id = normalizeChainId(chainId);
const unsupported = this.isChainUnsupported(id);
this.emit('change', { chain: { id, unsupported } });
}

protected onDisconnect() {
this.emit('disconnect');
}
}

export { Web3OnboardConnectorBase };
66 changes: 66 additions & 0 deletions packages/common/src/connectors/base/onboard-injected-base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Chain } from '@wagmi/core';
import injectedModule from '@web3-onboard/injected-wallets';
import { InjectedWalletModule } from '@web3-onboard/injected-wallets/dist/types';
import injectedModuleWallets from '@web3-onboard/injected-wallets/dist/wallets';

import { getDevice } from '../../utils';
import {
BaseOptions,
Web3OnboardConnectorBase,
} from './onboard-base-connector';

export type InjectedBaseOptions = BaseOptions & {};

let availableInjectedWallets: InjectedWalletModule[] | undefined;

const getAvailableInjectedWallets = () => {
if (!availableInjectedWallets) {
availableInjectedWallets = injectedModule({})({
device: getDevice() as any,
}) as InjectedWalletModule[];
}

return availableInjectedWallets;
};

abstract class Web3OnboardInjectedConnectorBase<
Options extends InjectedBaseOptions = any,
> extends Web3OnboardConnectorBase<Options> {
walletModule!: InjectedWalletModule;

constructor(config: { chains?: Chain[]; options: Options }) {
super({ ...config, options: config.options });

this.getWalletModule().then((module) => {
this.walletModule = module;
this.name = module.label;

if (getAvailableInjectedWallets().find((w) => w.label === module.label)) {
this.available = true;
}
});
}

abstract selectModule(
wallets: InjectedWalletModule[],
): Promise<InjectedWalletModule | undefined>;

async getWalletModule(): Promise<InjectedWalletModule> {
if (!this.walletModule) {
const mod = await this.selectModule(injectedModuleWallets);

if (!mod) {
debugger;
throw new Error(
'No injected module returned from options.selectModule',
);
}

this.walletModule = mod;
}

return this.walletModule;
}
}

export { Web3OnboardInjectedConnectorBase };
17 changes: 17 additions & 0 deletions packages/common/src/connectors/binance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { InjectedWalletModule } from '@web3-onboard/injected-wallets/dist/types';

import { CustodyType } from '../types';
import { Web3OnboardInjectedConnectorBase } from './base/onboard-injected-base';

class Web3OnboardBinanceConnector extends Web3OnboardInjectedConnectorBase {
readonly id = 'web3onboard-binance';
custodyType = CustodyType.SELF_CUSTODY;

async selectModule(wallets: InjectedWalletModule[]) {
return wallets.find((w) => w.label.toLowerCase().includes('binance'));
}

switchChain = undefined;
}

export { Web3OnboardBinanceConnector };
15 changes: 15 additions & 0 deletions packages/common/src/connectors/brave.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { InjectedWalletModule } from '@web3-onboard/injected-wallets/dist/types';

import { CustodyType } from '../types';
import { Web3OnboardInjectedConnectorBase } from './base/onboard-injected-base';

class Web3OnboardBraveConnector extends Web3OnboardInjectedConnectorBase {
readonly id = 'web3onboard-brave';
custodyType = CustodyType.SELF_CUSTODY;

async selectModule(wallets: InjectedWalletModule[]) {
return wallets.find((w) => w.label.toLowerCase().includes('brave'));
}
}

export { Web3OnboardBraveConnector };
Loading

0 comments on commit 3f6f94b

Please sign in to comment.