Skip to content

Commit

Permalink
refactor: Lazy instantiation of adapters
Browse files Browse the repository at this point in the history
  • Loading branch information
gin-lsl committed May 20, 2024
1 parent 3b162c6 commit 3bd5d95
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 150 deletions.
5 changes: 0 additions & 5 deletions packages/assets/src/wallets/solflare.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,3 @@ export const metadata_Solflare: WalletMetadata = {
},
],
};

export const metadata_SolflareMetaMaskSnap: WalletMetadata & { isMetaMaskSnap: true } = {
...metadata_Solflare,
isMetaMaskSnap: true,
};
12 changes: 6 additions & 6 deletions packages/solana/src/solana-provider/config-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface AntDesignWeb3ConfigProviderProps {
availableChains: SolanaChainConfig[];
balance?: boolean;
currentChain?: SolanaChainConfig;
availableWallets: Wallet[];
availableWallets?: Wallet[];
connectionError?: WalletConnectionError;
autoAddRegisteredWallets?: boolean;
onCurrentChainChange?: (chain?: SolanaChainConfig) => void;
Expand Down Expand Up @@ -137,8 +137,8 @@ export const AntDesignWeb3ConfigProvider: React.FC<
.filter((item) => item !== null) as (Chain & SolanaChainConfig)[];
}, [props.availableChains, props.chainAssets]);

const availableWallets = useMemo<Wallet[]>(() => {
const providedWallets = props.availableWallets.map<Wallet>((w) => {
const availableWallets = useMemo<Wallet[] | undefined>(() => {
const providedWallets = props.availableWallets?.map<Wallet>((w) => {
const adapter = wallets?.find((item) => item.adapter.name === w.name)?.adapter;
const isWalletConnectAdapter = adapter instanceof WalletConnectWalletAdapter;

Expand All @@ -161,10 +161,10 @@ export const AntDesignWeb3ConfigProvider: React.FC<
return providedWallets;
}

const providedWalletNames = providedWallets.map((w) => w.name);
const providedWalletNames = providedWallets?.map((w) => w.name);

const autoRegisteredWallets = wallets
.filter((w) => !providedWalletNames.includes(w.adapter.name))
.filter((w) => !providedWalletNames?.includes(w.adapter.name))
.map<Wallet>((w) => {
const adapter = w.adapter;

Expand All @@ -182,7 +182,7 @@ export const AntDesignWeb3ConfigProvider: React.FC<
};
});

return [...providedWallets, ...autoRegisteredWallets];
return [...(providedWallets || []), ...(autoRegisteredWallets || [])];
}, [props.availableWallets, wallets, props.autoAddRegisteredWallets]);

const currentChain = useMemo(() => {
Expand Down
106 changes: 53 additions & 53 deletions packages/solana/src/solana-provider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo, useState, type FC, type PropsWithChildren } from 'react';
import { useEffect, useMemo, useState, type FC, type PropsWithChildren } from 'react';
import { Solana, SolanaDevnet, SolanaTestnet } from '@ant-design/web3-assets/solana';
import type { Locale } from '@ant-design/web3-common';
import type { Locale, Wallet } from '@ant-design/web3-common';
import { WalletConnectionError } from '@solana/wallet-adapter-base';
import {
ConnectionProvider,
Expand All @@ -11,15 +11,15 @@ import {
import { type UniversalProviderOpts } from '@walletconnect/universal-provider';

import { solana, type SolanaChainConfig } from '../chains';
import { isAdapterWalletFactory, isWalletConnectFactory } from '../utils';
import { isAdapterWallet, isWalletConnectWallet } from '../utils';
import { type WalletFactory } from '../wallets/types';
import { AntDesignWeb3ConfigProvider } from './config-provider';
import { useWalletConnectProvider } from './useWalletConnectProvider';

export interface SolanaWeb3ConfigProviderProps {
locale?: Locale;
chains?: SolanaChainConfig[];
wallets?: WalletFactory[];
wallets: WalletFactory[];
balance?: boolean;

autoAddRegisteredWallets?: boolean;
Expand All @@ -41,7 +41,7 @@ export interface SolanaWeb3ConfigProviderProps {
export const SolanaWeb3ConfigProvider: FC<PropsWithChildren<SolanaWeb3ConfigProviderProps>> = ({
locale,
chains = [solana],
wallets: walletFactories = [],
wallets: walletFactories,
balance,
rpcProvider,
connectionConfig,
Expand All @@ -55,6 +55,8 @@ export const SolanaWeb3ConfigProvider: FC<PropsWithChildren<SolanaWeb3ConfigProv
const [connectionError, setConnectionError] = useState<WalletConnectionError>();
const walletConnectProviderGetter = useWalletConnectProvider(walletConnect);

const [walletInstances, setWalletInstances] = useState<Wallet[]>();

const endpoint = useMemo(() => {
if (typeof rpcProvider === 'function') {
return rpcProvider(currentChain);
Expand All @@ -63,59 +65,57 @@ export const SolanaWeb3ConfigProvider: FC<PropsWithChildren<SolanaWeb3ConfigProv
return (currentChain ?? solana).rpcUrls.default;
}, [rpcProvider, currentChain]);

const availableWallets = walletFactories.map((factory) =>
factory.create(walletConnectProviderGetter),
);
useEffect(() => {
const allWallets = walletFactories.map((factory) => factory.create());

// Only filter out the wallets that have an adapter
const walletAdapters = useMemo(
() =>
walletFactories
.filter(isAdapterWalletFactory)

.map((w) => {
if (isWalletConnectFactory(w)) {
w.adapter.setWalletConnectProviderGetter(walletConnectProviderGetter);
w.adapter.setWalletConnectConfigGetter(() => ({
walletConnect,
currentChain,
rpcEndpoint: endpoint,
}));
}

return w.adapter;
}),
[currentChain, endpoint, walletConnect, walletConnectProviderGetter, walletFactories],
);
setWalletInstances(allWallets);
}, [walletFactories]);

const availableWalletAdapters = useMemo(() => {
return walletInstances?.filter(isAdapterWallet).map((w) => {
if (isWalletConnectWallet(w)) {
w.adapter.setWalletConnectProviderGetter(walletConnectProviderGetter);
w.adapter.setWalletConnectConfigGetter(() => ({
walletConnect,
currentChain,
rpcEndpoint: endpoint,
}));
}

return w.adapter!;
});
}, [currentChain, endpoint, walletConnect, walletConnectProviderGetter, walletInstances]);

return (
<ConnectionProvider endpoint={endpoint} config={connectionConfig}>
<WalletProvider
wallets={walletAdapters}
autoConnect={autoConnect}
{...walletProviderProps}
onError={(error, adapter) => {
if (error instanceof WalletConnectionError) {
setConnectionError(error);
}

walletProviderProps?.onError?.(error, adapter);
}}
>
<AntDesignWeb3ConfigProvider
locale={locale}
chainAssets={[Solana, SolanaDevnet, SolanaTestnet]}
availableWallets={availableWallets}
balance={balance}
currentChain={currentChain}
onCurrentChainChange={(chain) => setCurrentChain(chain)}
availableChains={chains}
connectionError={connectionError}
autoAddRegisteredWallets={autoAddRegisteredWallets}
{!!availableWalletAdapters && (
<WalletProvider
wallets={availableWalletAdapters}
autoConnect={autoConnect}
{...walletProviderProps}
onError={(error, adapter) => {
if (error instanceof WalletConnectionError) {
setConnectionError(error);
}

walletProviderProps?.onError?.(error, adapter);
}}
>
{children}
</AntDesignWeb3ConfigProvider>
</WalletProvider>
<AntDesignWeb3ConfigProvider
locale={locale}
chainAssets={[Solana, SolanaDevnet, SolanaTestnet]}
availableWallets={walletInstances}
balance={balance}
currentChain={currentChain}
onCurrentChainChange={(chain) => setCurrentChain(chain)}
availableChains={chains}
connectionError={connectionError}
autoAddRegisteredWallets={autoAddRegisteredWallets}
>
{children}
</AntDesignWeb3ConfigProvider>
</WalletProvider>
)}
</ConnectionProvider>
);
};
28 changes: 19 additions & 9 deletions packages/solana/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import type { Wallet } from '@ant-design/web3-common';
import { WalletReadyState } from '@solana/wallet-adapter-base';

import type {
AdapterWalletFactory as AdapterWalletFactoryType,
WalletConnectWalletFactory as WalletConnectWalletFactoryType,
AdapterWallet,
MetaMaskSnapWalletFactory as MetaMaskSnapWalletFactoryType,
StandardWallet,
WalletConnectWallet,
WalletFactory as WalletFactoryType,
} from './wallets/types';

export const hasWalletReady = (readyState?: WalletReadyState) =>
readyState === WalletReadyState.Installed || readyState === WalletReadyState.Loadable;

export const isWalletConnectFactory = (
export const isMetaMaskSnapWalletFactory = (
factory: WalletFactoryType,
): factory is WalletConnectWalletFactoryType =>
!!(factory as WalletConnectWalletFactoryType).isWalletConnect;
): factory is MetaMaskSnapWalletFactoryType => {
return (factory as MetaMaskSnapWalletFactoryType).isMetaMaskSnap === true;
};

export const isAdapterWalletFactory = (
factory: WalletFactoryType,
): factory is AdapterWalletFactoryType => {
return (factory as AdapterWalletFactoryType).adapter !== undefined;
export const isStandardWallet = (wallet: Wallet): wallet is StandardWallet => {
return (wallet as StandardWallet).isStandardWallet === true;
};

export const isAdapterWallet = (wallet: Wallet): wallet is AdapterWallet => {
return (wallet as AdapterWallet).adapter !== undefined;
};

export const isWalletConnectWallet = (wallet: Wallet): wallet is WalletConnectWallet => {
return (wallet as WalletConnectWallet).isWalletConnect !== undefined;
};
31 changes: 14 additions & 17 deletions packages/solana/src/wallets/built-in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,26 @@ import {
metadata_OkxWallet,
metadata_Phantom,
metadata_Solflare,
metadata_SolflareMetaMaskSnap,
metadata_Trust,
metadata_WalletConnect,
} from '@ant-design/web3-assets';
import {
CoinbaseWalletAdapter,
SolflareWalletAdapter,
TrustWalletAdapter,
} from '@solana/wallet-adapter-wallets';
import { CoinbaseWalletAdapter, TrustWalletAdapter } from '@solana/wallet-adapter-wallets';

import { WalletConnectWalletAdapter } from '../wallet-connect-adapter';
import { StandardWalletFactory, WalletConnectWalletFactory, WalletFactory } from './factory';

export const CoinbaseWallet = () =>
WalletFactory(new CoinbaseWalletAdapter(), metadata_CoinbaseWallet);
export const TrustWallet = () => WalletFactory(new TrustWalletAdapter(), metadata_Trust);
export const SolflareMetaMaskSnapWallet = () =>
WalletFactory(new SolflareWalletAdapter(), metadata_SolflareMetaMaskSnap);
export const CoinbaseWallet = WalletFactory(
() => new CoinbaseWalletAdapter(),
metadata_CoinbaseWallet,
);
export const TrustWallet = WalletFactory(() => new TrustWalletAdapter(), metadata_Trust);

export const PhantomWallet = () => StandardWalletFactory(metadata_Phantom);
export const OKXWallet = () => StandardWalletFactory(metadata_OkxWallet);
export const BackpackWallet = () => StandardWalletFactory(metadata_Backpack);
export const SolflareWallet = () => StandardWalletFactory(metadata_Solflare);
export const PhantomWallet = StandardWalletFactory(metadata_Phantom);
export const OKXWallet = StandardWalletFactory(metadata_OkxWallet);
export const BackpackWallet = StandardWalletFactory(metadata_Backpack);
export const SolflareWallet = StandardWalletFactory(metadata_Solflare);

export const WalletConnectWallet = () =>
WalletConnectWalletFactory(new WalletConnectWalletAdapter(), metadata_WalletConnect);
export const WalletConnectWallet = WalletConnectWalletFactory(
new WalletConnectWalletAdapter(),
metadata_WalletConnect,
);
90 changes: 49 additions & 41 deletions packages/solana/src/wallets/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,35 @@ import type {
WalletFactoryBuilder,
} from './types';

export const WalletFactory: WalletFactoryBuilder = (adapter, metadata) => {
return {
adapter,
create: () => {
return {
...metadata,
name: adapter.name,
remark: metadata.remark,
adapter: adapter,
};
},
export const WalletFactory: WalletFactoryBuilder = (adapterBuilder, metadata) => {
return () => {
return {
// adapter,
create: () => {
const adapter = typeof adapterBuilder === 'function' ? adapterBuilder() : adapterBuilder;

return {
...metadata,
name: adapter.name,
remark: metadata.remark,
adapter: adapter,
};
},
};
};
};

// For Standard wallets
export const StandardWalletFactory: StandardWalletFactoryBuilder = (metadata) => {
return {
create: () => {
return {
...metadata,
isStandardWallet: true,
};
},
return () => {
return {
create: () => {
return {
...metadata,
isStandardWallet: true,
};
},
};
};
};

Expand All @@ -35,32 +41,34 @@ export const WalletConnectWalletFactory: WalletConnectWalletFactoryBuilder = (
adapter,
metadata,
) => {
return {
isWalletConnect: true,
adapter,
create: (getWalletConnectProvider) => {
return {
...metadata,
name: adapter.name,
remark: metadata.remark,
adapter,
return () => {
return {
create: (getWalletConnectProvider) => {
return {
...metadata,
name: adapter.name,
remark: metadata.remark,

getQrCode: getWalletConnectProvider
? async () => {
const walletConnectProvider = await getWalletConnectProvider();
adapter,
isWalletConnect: true,

if (!walletConnectProvider) {
return Promise.reject(new Error('WalletConnect is not available'));
}
getQrCode: getWalletConnectProvider
? async () => {
const walletConnectProvider = await getWalletConnectProvider();

return new Promise((resolve) => {
walletConnectProvider.on('display_uri', (uri: string) => {
resolve({ uri });
if (!walletConnectProvider) {
return Promise.reject(new Error('WalletConnect is not available'));
}

return new Promise((resolve) => {
walletConnectProvider.on('display_uri', (uri: string) => {
resolve({ uri });
});
});
});
}
: undefined,
};
},
}
: undefined,
};
},
};
};
};
Loading

0 comments on commit 3bd5d95

Please sign in to comment.