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

refactor: wallets #1869

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
6 changes: 6 additions & 0 deletions .changeset/cyan-pens-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rainbow-me/rainbowkit": minor
"site": patch
---

Refactored and improved custom wallets for much easier implementation.
6 changes: 1 addition & 5 deletions packages/rainbowkit/src/wallets/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export type Wallet = {
desktop?: string;
};
hidden?: () => boolean;
createConnector: (walletDetails: WalletDetailsParams) => CreateConnectorFn;
createConnector: CreateConnectorFn;
} & RainbowKitConnector;

export interface DefaultWalletOptions {
Expand Down Expand Up @@ -117,10 +117,6 @@ export type RainbowKitDetails = Omit<Wallet, 'createConnector' | 'hidden'> & {

export type WalletDetailsParams = { rkDetails: RainbowKitDetails };

export type CreateConnector = (walletDetails: {
rkDetails: RainbowKitDetails;
}) => CreateConnectorFn;

// This is the default connector you get at first from wagmi
// "Connector" + rainbowkit details we inject into the connector
export type WagmiConnectorInstance = Connector & {
Expand Down
65 changes: 29 additions & 36 deletions packages/rainbowkit/src/wallets/connectorsForWallets.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need to refactor much of the code in the walletListItems for loop, as the spread operators and var naming is getting tough to understand. Need comments here too. Rewinding back to v1, it was a bit easier to read and had comments: https://github.com/rainbow-me/rainbowkit/blob/42b0661e622ba99ec98cdb0219431f90ca45d40d/packages/rainbowkit/src/wallets/connectorsForWallets.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored 🙏

Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { CreateConnectorFn } from 'wagmi';
import { createConnector as createWagmiConnector } from 'wagmi';
import { walletConnect } from 'wagmi/connectors';
import { isHexString } from '../utils/colors';
import { omitUndefinedValues } from '../utils/omitUndefinedValues';
import { uniqueBy } from '../utils/uniqueBy';
import type {
RainbowKitWalletConnectParameters,
Wallet,
WalletDetailsParams,
WalletList,
} from './Wallet';
import { computeWalletConnectMetaData } from './computeWalletConnectMetaData';
Expand Down Expand Up @@ -113,7 +114,7 @@ export const connectorsForWallets = (
);

for (const {
createConnector,
createConnector: createRainbowKitConnector,
groupIndex,
groupName,
hidden,
Expand All @@ -129,44 +130,36 @@ export const connectorsForWallets = (
}
}

const walletMetaData = (
// For now we should only use these as the additional parameters
additionalRkParams?: Pick<
WalletDetailsParams['rkDetails'],
'isWalletConnectModalConnector' | 'showQrModal'
>,
) => {
return {
rkDetails: omitUndefinedValues({
...walletMeta,
groupIndex,
groupName,
isRainbowKitConnector: true,
// These additional params will be used in rainbowkit react tree to
// merge `walletConnectWallet` and `walletConnect` connector from wagmi with
// showQrModal: true. This way we can let the user choose if they want to
// connect via QR code or open the official walletConnect modal instead
...(additionalRkParams ? additionalRkParams : {}),
}),
};
const rainbowKitDetails = {
rkDetails: omitUndefinedValues({
...walletMeta,
groupIndex,
groupName,
isRainbowKitConnector: true,
}),
};

const isWalletConnectConnector = walletMeta.id === 'walletConnect';

if (isWalletConnectConnector) {
connectors.push(
createConnector(
walletMetaData({
isWalletConnectModalConnector: true,
showQrModal: true,
}),
),
);
}

const connector = createConnector(walletMetaData());
const connector = createWagmiConnector((config) => ({
...createRainbowKitConnector(config),
...rainbowKitDetails,
}));

connectors.push(connector);

if (walletMeta.id === 'walletConnect') {
const walletConnectConnector = createWagmiConnector((config) => ({
...walletConnect({
projectId,
metadata: walletConnectMetaData,
...walletConnectParameters,
showQrModal: true,
})(config),
...rainbowKitDetails,
isWalletConnectModalConnector: true,
}));

connectors.push(walletConnectConnector);
}
magiziz marked this conversation as resolved.
Show resolved Hide resolved
}

return connectors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ describe('getInjectedConnector', () => {
it('only rainbow provider', () => {
window.ethereum = { isMetaMask: true, isRainbow: true };
const connector = getInjectedConnector({
id: 'rainbow',
name: 'Rainbow',
flag: 'isRainbow',
});
expect(!!connector).toEqual(true);
Expand All @@ -16,6 +18,8 @@ describe('getInjectedConnector', () => {
it('only metamask provider', () => {
window.ethereum = { isMetaMask: true };
const connector = getInjectedConnector({
id: 'metamask',
name: 'MetaMask',
flag: 'isMetaMask',
});
expect(!!connector).toEqual(true);
Expand Down
61 changes: 35 additions & 26 deletions packages/rainbowkit/src/wallets/getInjectedConnector.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import { createConnector } from 'wagmi';
import { CreateConnectorFn } from 'wagmi';
import { injected } from 'wagmi/connectors';
import { CreateConnector, WalletDetailsParams } from './Wallet';

interface CreateInjectedConnectorParameters {
id: string;
name: string;
provider?: any;
}

interface GetInjectedConnectorParameters {
id: string;
name: string;
flag?: string;
namespace?: string;
target?: any;
}

/*
* Returns the explicit window provider that matches the flag and the flag is true
Expand Down Expand Up @@ -75,36 +88,32 @@ function getInjectedProvider({
return window.ethereum;
}

function createInjectedConnector(provider?: any): CreateConnector {
return (walletDetails: WalletDetailsParams) => {
// Create the injected configuration object conditionally based on the provider.
const injectedConfig = provider
? {
target: () => ({
id: walletDetails.rkDetails.id,
name: walletDetails.rkDetails.name,
provider,
}),
}
: {};
function createInjectedConnector({
id,
name,
provider,
}: CreateInjectedConnectorParameters) {
// Create the injected configuration object conditionally based on the provider.
const injectedConfig = provider
? {
target: () => ({
id,
name,
provider,
}),
Comment on lines +104 to +106
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Those return types are required in wagmi. Reference to the docs here.

}
: {};

return createConnector((config) => ({
// Spread the injectedConfig object, which may be empty or contain the target function
...injected(injectedConfig)(config),
...walletDetails,
}));
};
return injected(injectedConfig);
}

export function getInjectedConnector({
id,
name,
flag,
namespace,
target,
}: {
flag?: string;
namespace?: string;
target?: any;
}): CreateConnector {
}: GetInjectedConnectorParameters): CreateConnectorFn {
const provider = target ? target : getInjectedProvider({ flag, namespace });
return createInjectedConnector(provider);
return createInjectedConnector({ id, name, provider });
}
59 changes: 8 additions & 51 deletions packages/rainbowkit/src/wallets/getWalletConnectConnector.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
import { createConnector } from 'wagmi';
import type { CreateConnectorFn } from 'wagmi';
import { WalletConnectParameters, walletConnect } from 'wagmi/connectors';
import type {
CreateConnector,
RainbowKitDetails,
RainbowKitWalletConnectParameters,
WalletDetailsParams,
} from './Wallet';
import type { RainbowKitWalletConnectParameters } from './Wallet';

interface GetWalletConnectConnectorParams {
projectId: string;
walletConnectParameters?: RainbowKitWalletConnectParameters;
}

interface CreateWalletConnectConnectorParams {
projectId: string;
walletDetails: WalletDetailsParams;
walletConnectParameters?: RainbowKitWalletConnectParameters;
}

interface GetOrCreateWalletConnectInstanceParams {
projectId: string;
walletConnectParameters?: RainbowKitWalletConnectParameters;
rkDetailsShowQrModal?: RainbowKitDetails['showQrModal'];
}

const walletConnectInstances = new Map<
Expand All @@ -34,21 +21,13 @@ const walletConnectInstances = new Map<
const getOrCreateWalletConnectInstance = ({
projectId,
walletConnectParameters,
rkDetailsShowQrModal,
}: GetOrCreateWalletConnectInstanceParams): ReturnType<
typeof walletConnect
> => {
let config: WalletConnectParameters = {
}: GetOrCreateWalletConnectInstanceParams): CreateConnectorFn => {
const config: WalletConnectParameters = {
...(walletConnectParameters ? walletConnectParameters : {}),
projectId,
showQrModal: false, // Required. Otherwise WalletConnect modal (Web3Modal) will popup during time of connection for a wallet
};

// `rkDetailsShowQrModal` should always be `true`
if (rkDetailsShowQrModal) {
config = { ...config, showQrModal: true };
}

const serializedConfig = JSON.stringify(config);

const sharedWalletConnector = walletConnectInstances.get(serializedConfig);
Expand All @@ -65,30 +44,11 @@ const getOrCreateWalletConnectInstance = ({
return newWalletConnectInstance;
};

// Creates a WalletConnect connector with the given project ID and additional options.
function createWalletConnectConnector({
projectId,
walletDetails,
walletConnectParameters,
}: CreateWalletConnectConnectorParams): CreateConnectorFn {
// Create and configure the WalletConnect connector with project ID and options.
return createConnector((config) => ({
...getOrCreateWalletConnectInstance({
projectId,
walletConnectParameters,
// Used in `connectorsForWallets` to add another
// walletConnect wallet into rainbowkit with modal popup option
rkDetailsShowQrModal: walletDetails.rkDetails.showQrModal,
})(config),
...walletDetails,
}));
}

// Factory function to obtain a configured WalletConnect connector.
export function getWalletConnectConnector({
projectId,
walletConnectParameters,
}: GetWalletConnectConnectorParams): CreateConnector {
}: GetWalletConnectConnectorParams): CreateConnectorFn {
// We use this projectId in place of YOUR_PROJECT_ID for our examples.
// This allows us our examples and templates to be functional with WalletConnect v2.
// We warn developers against using this projectId in their dApp in production.
Expand All @@ -104,11 +64,8 @@ export function getWalletConnectConnector({
projectId = exampleProjectId;
}

// Return a function that merges additional wallet details with `CreateConnectorFn`.
return (walletDetails: WalletDetailsParams) =>
createWalletConnectConnector({
projectId,
walletDetails,
walletConnectParameters,
});
return getOrCreateWalletConnectInstance({
projectId,
walletConnectParameters,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const bifrostWallet = ({
walletConnectParameters,
})
: getInjectedConnector({
id: 'bifrostWallet',
name: 'Bifrost Wallet',
flag: 'isBifrost',
}),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export const bitgetWallet = ({
walletConnectParameters,
})
: getInjectedConnector({
id: 'bitget',
name: 'Bitget Wallet',
namespace: 'bitkeep.ethereum',
flag: 'isBitKeep',
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@ export const bitskiWallet = (): Wallet => ({
],
},
},
createConnector: getInjectedConnector({ flag: 'isBitski' }),
createConnector: getInjectedConnector({
id: 'bitski',
name: 'Bitski',
flag: 'isBitski',
}),
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ export const braveWallet = (): Wallet => ({
// more of a convenience for users who are already using Brave rather than
// an explicit wallet choice for users coming from other browsers.
},
createConnector: getInjectedConnector({ flag: 'isBraveWallet' }),
createConnector: getInjectedConnector({
id: 'brave',
name: 'Brave Wallet',
flag: 'isBraveWallet',
}),
});
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ export const bybitWallet = ({
walletConnectParameters,
})
: getInjectedConnector({
id: 'bybit',
name: 'Bybit Wallet',
namespace: 'bybitWallet',
}),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ export const clvWallet = ({
projectId,
walletConnectParameters,
})
: getInjectedConnector({ namespace: 'clover' }),
: getInjectedConnector({ id: 'clv', name: 'CLV', namespace: 'clover' }),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export const coin98Wallet = ({
walletConnectParameters,
})
: getInjectedConnector({
id: 'coin98',
name: 'Coin98 Wallet',
namespace: 'coin98Wallet',
flag: 'isCoin98',
}),
Expand Down