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 dynamic wallet #2838

Open
wants to merge 45 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
8d83d85
Add dynamic wallet
Alex99y Oct 14, 2024
20859c4
Update dynamic wallet
Alex99y Nov 12, 2024
358ecc9
Merge branch 'development' into feat/integrate-dynamic-wallet
Alex99y Nov 12, 2024
ef9c758
Integrate Dynamic Wallet
Alex99y Nov 25, 2024
1b05728
Update dynamic wallet library version
Alex99y Nov 25, 2024
acbcca1
Fix DW issue on connect wallet options
Alex99y Nov 25, 2024
b1b3673
Fix redux icon and dynamic wallet disconnect
Alex99y Nov 26, 2024
5156929
Fix swap issue
Alex99y Nov 27, 2024
f6bd9ab
Rework connectWallet and fix switchNetwork bug
Alex99y Nov 27, 2024
308413b
Fix getSigner issue
Alex99y Nov 27, 2024
b5fd632
Remove selected and connected wallets from wallet options dynamic wallet
Alex99y Nov 27, 2024
a4a598e
Reuse existing session for DW already connected
Alex99y Nov 28, 2024
76950f0
Persist dynamic wallet sessions
Alex99y Nov 29, 2024
21d0d01
Fix persisting connected wallet issue
Alex99y Nov 29, 2024
620162d
Fix onDisconnect issue when the account has been changed
Alex99y Dec 2, 2024
fc351b2
Fix auto sidebar open
Alex99y Dec 2, 2024
1bd84d8
Fix manually disconnect bug
Alex99y Dec 2, 2024
2399ecd
Fix swapConnections error and avoid reconnecting wallets
Alex99y Dec 5, 2024
69aab12
Add chain filter
Alex99y Dec 5, 2024
1d12de1
Remove onChainRef
Alex99y Dec 9, 2024
1d03fb0
Remove cosmos connector
Alex99y Dec 9, 2024
95a4e99
Merge branch 'development' into feat/integrate-dynamic-wallet
Alex99y Dec 9, 2024
faedce3
Fix minor dynamic wallet issues
Alex99y Dec 9, 2024
9972399
Add new DW configs for MAINNET and TESTNET networks.
Alex99y Dec 13, 2024
63155af
Update dynamic wallet to the latest version
Alex99y Dec 20, 2024
221c2f8
Merge branch 'development' into feat/integrate-dynamic-wallet
Alex99y Dec 20, 2024
82bbcfc
Fix package-lock.json
Alex99y Dec 20, 2024
22ae6fc
Add safe wallet
Alex99y Dec 20, 2024
63f6978
Select specific evm wallets
Alex99y Dec 23, 2024
a6e51a4
Remove invalid wallets and fix them
Alex99y Dec 23, 2024
0b9381d
Merge branch 'development' into feat/integrate-dynamic-wallet
Alex99y Jan 8, 2025
8a76caa
Fix Readonly wallet merge issues
Alex99y Jan 8, 2025
3b68ad3
lint
Alex99y Jan 8, 2025
5ecfc85
Add method getWalletOptions to useEffect array dependencies
Alex99y Jan 8, 2025
98d856f
Rework submitAddress method
Alex99y Jan 9, 2025
18d1a0f
Update DynamicWallet sdk to the latest version and remove WA for EVM …
Alex99y Jan 9, 2025
bf60bb5
Validate the connected wallet chain
Alex99y Jan 9, 2025
db0833e
Remove few TODO comments
Alex99y Jan 10, 2025
af6f86e
Separe ReadOnlyWallet creation
Alex99y Jan 10, 2025
37fe8e3
PR review fixes
Alex99y Jan 15, 2025
e05fda0
eslint fixes
Alex99y Jan 15, 2025
542c993
Update dynamic wallet package
Alex99y Jan 21, 2025
2367b81
Merge branch 'development' into feat/integrate-dynamic-wallet
Alex99y Jan 21, 2025
73f345b
Fix package-lock.json
Alex99y Jan 21, 2025
8e3fdf1
Merge branch 'development' into feat/integrate-dynamic-wallet
Alex99y Feb 5, 2025
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
35,808 changes: 20,896 additions & 14,912 deletions wormhole-connect/package-lock.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions wormhole-connect/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
"@aptos-labs/ts-sdk": "^1.33.1",
"@aptos-labs/wallet-adapter-core": "^4.23.0",
"@coral-xyz/anchor": "^0.29.0",
"@dynamic-labs/ethereum": "^4.2.3",
"@dynamic-labs/ethers-v6": "^4.2.3",
"@dynamic-labs/sdk-react-core": "^4.2.3",
"@dynamic-labs/solana": "^4.2.3",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@ledgerhq/devices": "6.27.1",
Expand Down Expand Up @@ -48,8 +52,6 @@
"@wormhole-foundation/sdk-solana-ntt": "^0.6.1",
"@xlabs-libs/wallet-aggregator-aptos": "^1.0.0-alpha.2",
"@xlabs-libs/wallet-aggregator-core": "^0.0.1-alpha.22",
"@xlabs-libs/wallet-aggregator-evm": "^0.0.2-alpha.5",
"@xlabs-libs/wallet-aggregator-solana": "^0.0.1-alpha.15",
"@xlabs-libs/wallet-aggregator-sui": "^0.0.1-alpha.10",
"axios": "1.4.0",
"binary-parser": "^2.2.1",
Expand All @@ -65,6 +67,7 @@
"sha3": "^2.1.4",
"tss-react": "^4.7.7",
"use-debounce": "^9.0.4",
"viem": "^2.21.51",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
5 changes: 4 additions & 1 deletion wormhole-connect/src/WormholeConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ErrorBoundary from './components/ErrorBoundary';
import { WormholeConnectConfig } from './config/types';
import { WormholeConnectTheme } from 'theme';
import { RouteProvider } from './contexts/RouteContext';
import { WalletManagerProvider } from 'contexts/WalletManager';
import { TokensProvider } from './contexts/TokensContext';

export interface WormholeConnectProps {
Expand All @@ -39,7 +40,9 @@ export default function WormholeConnect({
<ErrorBoundary>
<TokensProvider>
<RouteProvider>
<AppRouter config={config} />
<WalletManagerProvider>
<AppRouter config={config} />
</WalletManagerProvider>
</RouteProvider>
</TokensProvider>
</ErrorBoundary>
Expand Down
13 changes: 11 additions & 2 deletions wormhole-connect/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import MAINNET from './mainnet';
import TESTNET from './testnet';
import DEVNET from './devnet';
import type { WormholeConnectConfig } from './types';
import type { DynamicWalletConfig, WormholeConnectConfig } from './types';
import { InternalConfig } from './types';
import { mergeCustomWrappedTokens, validateDefaults } from './utils';
import { wrapEventHandler } from './events';
Expand Down Expand Up @@ -79,6 +79,13 @@ export function buildConfig(
validateDefaults(customConfig.ui.defaultInputs, networkData.chains, tokens);
}

const isMainnet = network === 'Mainnet';

const dynamicWalletConfig: DynamicWalletConfig = {
environmentId: isMainnet
? '12430fd8-3f08-42d3-9b7c-7c70c66535b3'
: 'b1f4a038-1092-4656-b91d-e61648740572',
};
const ui = createUiConfig(customConfig.ui ?? {});

if (
Expand All @@ -96,7 +103,7 @@ export function buildConfig(
sdkConfig,

network,
isMainnet: network === 'Mainnet',
isMainnet,

// External resources
rpcs,
Expand Down Expand Up @@ -160,6 +167,8 @@ export function buildConfig(
// Guardian Set
guardianSet: networkData.guardianSet,

// Dynamic Wallet
dynamicWalletConfig,
// Transaction settings
transactionSettings: customConfig?.transactionSettings || {},
};
Expand Down
7 changes: 7 additions & 0 deletions wormhole-connect/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,16 @@ export interface InternalConfig<N extends Network> {

guardianSet: GuardianSetData;

// Dynamic Wallet
dynamicWalletConfig: DynamicWalletConfig;

transactionSettings: TransactionSettings;
}

export interface DynamicWalletConfig {
environmentId: string
}

export type TokenConfig = {
symbol: string;
name?: string;
Expand Down
287 changes: 287 additions & 0 deletions wormhole-connect/src/contexts/WalletManager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
import React, { Fragment, useRef } from 'react';
import { Chain as WormholeChain, isChain } from '@wormhole-foundation/sdk';
import { Theme } from '@mui/material';
import WalletSidebar from 'views/v2/Bridge/WalletConnector/Sidebar';
import {
TransferWallet,
useConnectToLastUsedWallet,
WalletData,
} from '../utils/wallet';
import { useDispatch } from 'react-redux';
import {
swapWallets,
disconnectWallet as disconnectWalletFromStore,
} from 'store/wallet';
import {
DynamicWallet,
isChainSupportedByDynamicWallet,
isDynamicWallet,
} from 'utils/dynamic-wallet/utils';
import { ConfiguredDynamicContext } from 'utils/dynamic-wallet/DynamicContext';
import {
useDynamicWalletHelpers,
useDynamicWalletOptions,
} from 'utils/dynamic-wallet/useDynamicWallet';
import {
ConnectedWallet,
toConnectedWallet,
Wallet,
} from 'utils/wallet/wallet';
import { getWalletOptions as getWalletAgreggatorOptions } from 'utils/wallet/legacy/index';
import { ChainConfig } from 'sdklegacy';
import config from 'config';
import { isReadOnlyWallet } from 'utils/wallet/ReadOnlyWallet';

interface WalletManagerProps {
connectWallet: (type: TransferWallet) => any;
getConnectedWallet: (type: TransferWallet) => ConnectedWallet | undefined;
switchChain: (chainId: number, type: TransferWallet) => Promise<void>;
getWalletOptions: (chain: ChainConfig | undefined) => Promise<WalletData[]>;
registerWalletSigner: (
chain: WormholeChain,
type: TransferWallet,
) => Promise<void>;
swapWalletConnections: () => void;
disconnectWallet: (type: TransferWallet) => Promise<void>;
}
interface ConnectedWallets {
sending?: ConnectedWallet;
receiving?: ConnectedWallet;
nextTypeToConnect: TransferWallet;
}

const WALLET_MANAGER_INITIAL_STATE: WalletManagerProps = {
connectWallet: (type: TransferWallet) => {},

Check failure on line 54 in wormhole-connect/src/contexts/WalletManager.tsx

View workflow job for this annotation

GitHub Actions / lint

Unexpected empty method 'connectWallet'
getConnectedWallet: (type: TransferWallet) => undefined,
switchChain: (chainId: number, type: TransferWallet) => Promise.resolve(),
getWalletOptions: (chain: ChainConfig | undefined) => Promise.resolve([]),
registerWalletSigner: (chain: WormholeChain, type: TransferWallet) =>
Promise.resolve(),
swapWalletConnections: () => undefined,
disconnectWallet: (type: TransferWallet) => Promise.resolve(),
} as const;
const WalletManager = React.createContext<WalletManagerProps>(
WALLET_MANAGER_INITIAL_STATE,
);

const useWalletManager = () => {
const context = React.useContext(WalletManager);
return context;
};
const defaultWalletSidebarConfig: { isOpen: boolean; type: TransferWallet } = {
isOpen: false,
type: TransferWallet.SENDING,
};

type OnConnectCallback = (wallet: DynamicWallet) => void;

interface InternalWMProviderProps {
onConnectCallbackRef: React.MutableRefObject<OnConnectCallback | undefined>;
}

const InternalWMComponent: React.FC<
React.PropsWithChildren<InternalWMProviderProps>
> = ({ children, onConnectCallbackRef }) => {
const { getDynamicWalletOptions, selectDynamicWalletOption } =
useDynamicWalletOptions();
const { disconnectDynamicWallet } = useDynamicWalletHelpers();
const [walletSidebarProps, setWalletSidebarProps] = React.useState<
typeof defaultWalletSidebarConfig
>(defaultWalletSidebarConfig);
const dynamicWormholeChainRef = React.useRef<WormholeChain>('Ethereum');
const dispatch = useDispatch();

const walletConnection = React.useRef<ConnectedWallets>({
nextTypeToConnect: TransferWallet.SENDING,
}).current;

const createConnectedWallet = React.useCallback(
async (wallet: Wallet, wormholeChain: WormholeChain): Promise<void> => {
walletConnection[walletConnection.nextTypeToConnect] =
await toConnectedWallet(
wallet,
walletConnection.nextTypeToConnect,
wormholeChain,
dispatch,
);
// TODO: Send disconnectWallet function to onDisconnectEvent of the wallet
// walletConnection[walletConnection.nextTypeToConnect].onDisconnect(disconnectWallet)
},
[walletConnection, disconnectDynamicWallet],

Check warning on line 110 in wormhole-connect/src/contexts/WalletManager.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useCallback has a missing dependency: 'dispatch'. Either include it or remove the dependency array
);

const sidebarOnConnectWallet = React.useCallback(
async (
walletInfo: WalletData,
type: TransferWallet,
chain: WormholeChain,
) => {
// TODO: `useLastConnectedWallet` is calling `sidebarOnConnectWallet` when the user clicks on swap wallets connections.
// We should not allow to connect the same wallet twice. The connection must persist.
walletConnection.nextTypeToConnect = type;
if ('walletKey' in walletInfo) {
// Saving the chain for `onConnectCallbackRef` callback because it is not available in the DynamicWallet object
dynamicWormholeChainRef.current = chain;
console.log(
'Dynamic Wallet will continue the connection flow',
walletInfo,
);
return await selectDynamicWalletOption(walletInfo.walletKey, (w) =>
createConnectedWallet(w, chain),
);
}

await createConnectedWallet(walletInfo, chain);
walletConnection.nextTypeToConnect = type;
if (walletSidebarProps.isOpen) {
setWalletSidebarProps(defaultWalletSidebarConfig);
}
},
[createConnectedWallet, selectDynamicWalletOption],

Check warning on line 140 in wormhole-connect/src/contexts/WalletManager.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useCallback has missing dependencies: 'walletConnection' and 'walletSidebarProps.isOpen'. Either include them or remove the dependency array
);

const getWalletOptions = React.useCallback(
async (chain: ChainConfig | undefined) => {
if (
chain &&
isChain(chain.key) &&
isChainSupportedByDynamicWallet(chain.key)
) {
return getDynamicWalletOptions(chain.key, walletConnection);
}

return getWalletAgreggatorOptions(chain);
},
[getDynamicWalletOptions],

Check warning on line 155 in wormhole-connect/src/contexts/WalletManager.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useCallback has a missing dependency: 'walletConnection'. Either include it or remove the dependency array
);

const registerWalletSigner = React.useCallback(
async (chain: WormholeChain, type: TransferWallet) => {
const w = walletConnection[type];
if (!w) throw new Error('must connect wallet');
const signer = await w.getSigner?.();
if (!signer) throw new Error('must have signer');
config.whLegacy.registerSigner(chain, signer);
},
[],

Check warning on line 166 in wormhole-connect/src/contexts/WalletManager.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useCallback has a missing dependency: 'walletConnection'. Either include it or remove the dependency array
);

const disconnectWallet = React.useCallback(
async (type: TransferWallet) => {
if (walletConnection[type]) {
const wallet = walletConnection[type].getWallet();
if (isDynamicWallet(wallet)) {
await disconnectDynamicWallet(wallet);
}
await walletConnection[type].disconnect();
walletConnection[type] = undefined;
dispatch(disconnectWalletFromStore(type));
}
},
[walletConnection, disconnectDynamicWallet],
);

const swapWalletConnections = React.useCallback(async () => {
const temp = walletConnection.sending;
walletConnection.sending = walletConnection.receiving;
walletConnection.receiving = temp;
walletConnection.nextTypeToConnect =
walletConnection.nextTypeToConnect === TransferWallet.SENDING
? TransferWallet.RECEIVING
: TransferWallet.SENDING;
dispatch(swapWallets());
if (isReadOnlyWallet(walletConnection.sending?.getWallet())) {
await disconnectWallet(TransferWallet.SENDING);
}
}, [walletConnection, dispatch]);

const connectWallet = React.useCallback(
async (type: TransferWallet) => {
walletConnection.nextTypeToConnect = type;
setWalletSidebarProps({ isOpen: true, type });
},
[setWalletSidebarProps],
);

const switchChain = React.useCallback(
async (chainId: number, type: TransferWallet) => {
await walletConnection[type]?.switchChain?.(chainId);
},
[walletConnection],
);

const getConnectedWallet = React.useCallback(
(type: TransferWallet) => {
return walletConnection[type];
},
[walletConnection],
);

const walletManager = React.useMemo(
() => ({
connectWallet,
getConnectedWallet,
switchChain,
getWalletOptions,
registerWalletSigner,
swapWalletConnections,
disconnectWallet,
}),
[
connectWallet,
getConnectedWallet,
switchChain,
registerWalletSigner,
getWalletOptions,
swapWalletConnections,
disconnectWallet,
],
);

React.useEffect(() => {
onConnectCallbackRef.current = async (wallet) => {
try {
await createConnectedWallet(wallet, dynamicWormholeChainRef.current);
} catch (err) {
// Something wrong happened here
console.log(err);
}
};
}, [createConnectedWallet]);

useConnectToLastUsedWallet(sidebarOnConnectWallet);

return (
<>
<WalletManager.Provider value={walletManager}>
{children}
<WalletSidebar
onConnectWallet={sidebarOnConnectWallet}
open={walletSidebarProps.isOpen}
type={walletSidebarProps.type}
onClose={() => setWalletSidebarProps(defaultWalletSidebarConfig)}
showAddressInput={
walletConnection.nextTypeToConnect === TransferWallet.RECEIVING
}
/>
</WalletManager.Provider>
</>
);
};

const WalletManagerProvider: React.FC<
React.PropsWithChildren<{ theme?: Theme }>
> = ({ children, theme }) => {
const onConnectRef = useRef<OnConnectCallback | undefined>(undefined);
return (
<Fragment>
<ConfiguredDynamicContext onConnectCallbackRef={onConnectRef}>
<InternalWMComponent onConnectCallbackRef={onConnectRef}>
{children}
</InternalWMComponent>
</ConfiguredDynamicContext>
</Fragment>
);
};

export { WalletManagerProvider, useWalletManager };
Loading
Loading