Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🦊🐺🐭 Add connectors #754

Closed
wants to merge 106 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
475c84a
Add context
dmaretskyi May 11, 2022
f59899b
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
May 17, 2022
048c972
Add connector logic and exports
May 18, 2022
f883491
Add connector example
May 18, 2022
75f986a
Add wallet connect example
May 18, 2022
bd54c05
Apply stash changes
Jun 27, 2022
84e8a55
Update depedencies
Jun 27, 2022
c17beb4
Merge branch 'master' into HEAD
Jun 27, 2022
7873f43
Remove ethers/providers
Jun 27, 2022
4e8dc7f
Merge branch 'dmaretskyi/connectors' of https://github.com/TrueFiEng/…
Jun 27, 2022
ef2490f
Fix lint
Jun 27, 2022
520287b
Fix lint
Jun 27, 2022
9f6f1f7
Merge branch 'master' into dmaretskyi/connectors
Jun 28, 2022
5b77f2a
Apply connector rebase
Jun 29, 2022
7c93e36
Remove transaction blocker
Jun 30, 2022
7208448
Merge branch 'master' into dmaretskyi/connectors
mj426382 Jun 30, 2022
b13347a
Merge branch 'master' into dmaretskyi/connectors
mj426382 Jul 5, 2022
1a13f3d
Add metamask by default
Jul 5, 2022
a7ac27c
Add testing wallet
Jul 6, 2022
0e88662
Add coinbase and portis connectors
Jul 6, 2022
a2b48cc
Merge branch 'dmaretskyi/connectors' of https://github.com/TrueFiEng/…
Jul 6, 2022
ebadd12
Add fortmatic wallet
Jul 7, 2022
f5ce29d
Add torus connector
Jul 7, 2022
f067124
Add brave and injected connectors
Jul 8, 2022
d80c170
Merge origin/master into dmaretskyi/connectors
rzadp Jul 13, 2022
e39343b
premerge
rzadp Jul 13, 2022
42b602c
Merge origin/master into dmaretskyi/connectors
rzadp Jul 13, 2022
76dcbdd
postmerge
rzadp Jul 13, 2022
0e2e45f
Remove types from deps
rzadp Jul 13, 2022
47cd9a9
Merge origin/master into dmaretskyi/connectors
rzadp Jul 13, 2022
0f2357b
Clean up a bit
yivlad Jul 15, 2022
7c282fc
Remov some wallets
yivlad Jul 15, 2022
ecc9f72
Debugging tests
yivlad Jul 15, 2022
b551f49
Merge branch 'master' into dmaretskyi/connectors
yivlad Jul 22, 2022
9c786dc
WIP
yivlad Jul 27, 2022
29b76e8
Add readonly provider as default
yivlad Jul 27, 2022
620761b
Green tests
yivlad Jul 27, 2022
c65cf20
Lint
yivlad Jul 27, 2022
09a3d2f
Green playwright tests
yivlad Jul 28, 2022
af7a59f
Lint
yivlad Jul 28, 2022
ecc4328
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Jul 28, 2022
2f1d594
Lint
yivlad Jul 28, 2022
feb07ab
Update tests
yivlad Jul 28, 2022
243cb46
Record example tests
yivlad Jul 29, 2022
170494e
Revert "Record example tests"
yivlad Jul 29, 2022
ad36415
Test ambire availability
yivlad Jul 29, 2022
13a343e
Bringa back playwright tests
yivlad Jul 29, 2022
f36cad8
Upload screenshot
yivlad Jul 29, 2022
9ca2988
Debug CI
yivlad Jul 29, 2022
4c43d06
Fix screenshot paths
yivlad Jul 29, 2022
4463cd5
Fix path again
yivlad Jul 29, 2022
b975f02
Wait for ambire page to show up
yivlad Jul 29, 2022
22710ce
Wait also for metamask page
yivlad Jul 29, 2022
c99be0a
Remove debugging stuff
yivlad Jul 29, 2022
bae12a6
Lint
yivlad Jul 29, 2022
892ba36
Start fixing example-next
yivlad Jul 29, 2022
80b7b36
Fix next playwright tests
yivlad Jul 29, 2022
0ae8081
Debgging swithicng chains
yivlad Aug 1, 2022
285034a
Fix docs tests
yivlad Aug 2, 2022
c265a72
Lint
yivlad Aug 2, 2022
f6d4ba4
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 2, 2022
ca7481a
Lint
yivlad Aug 2, 2022
4a82820
Check websocket provider
yivlad Aug 2, 2022
4bb5a6f
Fix timestamp overflow
yivlad Aug 3, 2022
749b6e5
Lint
yivlad Aug 3, 2022
a5f4080
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 3, 2022
3d96f46
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 3, 2022
f1c3d0e
Add test for switching accounts
yivlad Aug 5, 2022
bcb853e
Fix no multicall address error
yivlad Aug 8, 2022
de83617
Add logs
yivlad Aug 8, 2022
1c9255c
Fix change account issue
yivlad Aug 8, 2022
6397824
Lint
yivlad Aug 8, 2022
6778dbc
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 8, 2022
18cc041
Fix test order
yivlad Aug 8, 2022
7015a80
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 8, 2022
7da9027
Fix next tests
yivlad Aug 8, 2022
6ed9b2b
Fix ethers version mismatch
yivlad Aug 8, 2022
48c4869
Docs add timeout to playwright tests
yivlad Aug 8, 2022
1a959e2
deactivate function for connectors
yivlad Aug 9, 2022
670ef69
Example app add local provider only when testing
yivlad Aug 10, 2022
5640226
Fix coinabse wallet
yivlad Aug 10, 2022
cdcd19e
Bring bakc portis connector
yivlad Aug 10, 2022
16e599f
Lint
yivlad Aug 10, 2022
cdeb200
Reimplement polling interval logic
yivlad Aug 10, 2022
9cb87ac
Lint
yivlad Aug 10, 2022
9988309
USe typed events
yivlad Aug 10, 2022
e2d1db3
Don't use setImmediate
yivlad Aug 10, 2022
53e1c6d
Add apiNode connector
yivlad Aug 11, 2022
9dce9aa
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 11, 2022
aa7f725
Extract connectors to separate packages
yivlad Aug 11, 2022
02384ef
Set workspace dependecies properly
yivlad Aug 11, 2022
7ec4870
Fix CI
yivlad Aug 11, 2022
d55c53c
WIP
yivlad Aug 12, 2022
6ea9884
Make all tests green
yivlad Aug 17, 2022
05da578
Fix wallet provider non static calls tracking
yivlad Aug 17, 2022
8934edd
clear local storage
yivlad Aug 18, 2022
a38f556
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 18, 2022
d7a908d
Upgrade waffle
yivlad Aug 18, 2022
5fe407a
Delete tokens playwright tests
yivlad Aug 18, 2022
fda2c65
Fix playwright tests
yivlad Aug 18, 2022
1d830a3
Fix localStorage issue
yivlad Aug 19, 2022
e55fbca
Fix playwright tests
yivlad Aug 22, 2022
369ebde
Merge remote-tracking branch 'origin/master' into dmaretskyi/connectors
yivlad Aug 22, 2022
ee7d95d
Add transfer funds test
yivlad Aug 22, 2022
a6b375b
Lint
yivlad Aug 22, 2022
1c2582b
Make useEthers API backwards-compatible
yivlad Aug 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions packages/core/src/providers/network/connector/connector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { BaseProvider, Web3Provider } from '@ethersproject/providers';

export enum ConnectorPriority {
ApiNode = 1,
Wallet = 2,
}

export interface Update {
chainId: number
accounts: string[]
}

export type UpdateFn = (data: Update) => void

export interface Connector {
name: string;
priority: ConnectorPriority;

provider?: BaseProvider;

onUpdate?: UpdateFn;

connectEagerly(): Promise<void>

activate(): Promise<void>

deactivate(): Promise<void>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Connector } from "./connector";

export class ConnectorController {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should handle the lifecycle of the connector including chainID, accounts, block number etc.

Should have safeguards to protect from bugs in the connector implementation

constructor(
public readonly connector: Connector,
) {
connector.onUpdate = ({ chainId, accounts }) => {
this.chainId = chainId;
this.accounts = accounts;
}

void this.connector.connectEagerly();
}

public active = false;
public accounts: string[] = []
public chainId: number = 0

getProvider() {
return this.connector.provider;
}

async activate() {
await this.connector.activate();
this.active = true;
}

async deactivate() {
this.active = false;
await this.connector.deactivate();
}
}
41 changes: 41 additions & 0 deletions packages/core/src/providers/network/connector/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { createContext, ReactNode, useEffect, useState } from "react";
import { Connector } from "./connector";
import { ConnectorController } from "./connectorController";

interface ConnectorContextValue {
connectors: ConnectorController[];
addConnector(connector: Connector): void;
}

export const ConnectorContext = createContext<ConnectorContextValue | undefined>(undefined)

export interface ConnectorContextProviderProps {
connectors: Connector[];
children?: ReactNode;
}

export function ConnectorContextProvider({ connectors, children }: ConnectorContextProviderProps) {
const [controllers, setControllers] = useState<ConnectorController[]>([])

useEffect(() => {
const newControllers = connectors.map(connector => {
const existing = controllers.find(c => c.connector === connector)
if (existing) {
return existing
}
return new ConnectorController(connector)
})
const otherControllers = controllers.filter(c => !newControllers.some(c2 => c2.connector === c.connector))
setControllers([...newControllers, ...otherControllers].sort((a, b) => a.connector.priority - b.connector.priority))
}, connectors)

function addConnector(connector: Connector) {
setControllers(controllers.concat(new ConnectorController(connector)))
}

return (
<ConnectorContext.Provider value={{ connectors: controllers, addConnector }}>
{children}
</ConnectorContext.Provider>
)
}
38 changes: 38 additions & 0 deletions packages/core/src/providers/network/connector/impls/metamask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { BaseProvider, Web3Provider } from "@ethersproject/providers";
import { Connector, ConnectorPriority, UpdateFn } from "../connector";
import detectMetamask from '@metamask/detect-provider'

export class MetamaskConnector implements Connector {
public provider?: Web3Provider;
public priority = ConnectorPriority.Wallet;
public name = 'Metamask';

constructor() {

}

onUpdate?: UpdateFn;

private async init() {
const metamask = await detectMetamask();
this.provider = new Web3Provider(metamask as any);
}

async connectEagerly(): Promise<void> {
await this.init();

const chainId: string = await this.provider!.send('eth_chainId', [])
yivlad marked this conversation as resolved.
Show resolved Hide resolved
const accounts: string[] = await this.provider!.send('eth_accounts', [])
this.onUpdate?.({ chainId: parseInt(chainId), accounts });
}

async activate(): Promise<void> {
const chainId: string = await this.provider!.send('eth_chainId', [])
const accounts: string[] = await this.provider!.send('eth_requestAccounts', [])
this.onUpdate?.({ chainId: parseInt(chainId), accounts });
}

async deactivate(): Promise<void> {

}
}
27 changes: 27 additions & 0 deletions packages/core/src/providers/network/connector/impls/rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { BaseProvider, JsonRpcProvider, Web3Provider } from "@ethersproject/providers";
import { Connector, ConnectorPriority, UpdateFn } from "../connector";

export class RpcConnector implements Connector {
public provider: BaseProvider;
public priority = ConnectorPriority.ApiNode;
public name = 'RPC';

public onUpdate?: UpdateFn;

constructor(
public url: string,
) {
this.provider = new JsonRpcProvider(url);
}

async connectEagerly(): Promise<void> {
const { chainId } = await this.provider!.getNetwork();
this.onUpdate?.({ chainId, accounts: [] });
}
async activate(): Promise<void> {
const { chainId } = await this.provider!.getNetwork();
this.onUpdate?.({ chainId, accounts: [] });
}
async deactivate(): Promise<void> {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { BaseProvider } from "@ethersproject/providers";
import { useContext } from "react";
import { ConnectorController } from "./connectorController";
import { ConnectorContext } from "./context";

export interface UseProviderOptions {
chainId?: number;
account?: boolean | string;
}

export interface ConnectorNetwork {
chainId: number;
accounts: string[];
provider: BaseProvider;
}

export function useConnectorNetwork(opts: UseProviderOptions = {}): ConnectorNetwork | undefined {
const { connectors } = useContext(ConnectorContext)!;
const connector = connectors.find(c => matchConnector(opts, c));

if(!connector || !connector.getProvider()) {
return undefined;
}

return {
chainId: connector.chainId,
accounts: connector.accounts,
provider: connector.getProvider()!,
}
}

function matchConnector(opts: UseProviderOptions, connector: ConnectorController) {
if(opts.chainId) {
if(connector.chainId !== opts.chainId) {
return false;
}
}

if(opts.account === true) {
if(!connector.accounts.length) {
return false;
}
} else if(opts.account) {
if(!connector.accounts.includes(opts.account)) {
return false;
}
}

return true;
}