Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1,603 changes: 802 additions & 801 deletions bun.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"xrpl": "4.4.2"
},
"name": "swapkit-monorepo",
"overrides": { "libsodium-sumo": "0.7.15", "libsodium-wrappers-sumo": "0.7.15" },
"packageManager": "bun@^1.3.1",
"private": true,
"scripts": {
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { keepkeyBexWallet } from "@swapkit/wallets/keepkey-bex";
import { keplrWallet } from "@swapkit/wallets/keplr";
import { keystoreWallet } from "@swapkit/wallets/keystore";
import { ledgerWallet } from "@swapkit/wallets/ledger";
import { metamaskWallet } from "@swapkit/wallets/metamask";
import { walletSelectorWallet } from "@swapkit/wallets/near-wallet-selector";
import { okxWallet } from "@swapkit/wallets/okx";
import { onekeyWallet } from "@swapkit/wallets/onekey";
Expand Down Expand Up @@ -68,6 +69,7 @@ export {
keplrWallet,
keystoreWallet,
ledgerWallet,
metamaskWallet,
okxWallet,
onekeyWallet,
passkeysWallet,
Expand Down Expand Up @@ -105,6 +107,7 @@ export const defaultWallets = {
...keplrWallet,
...keystoreWallet,
...ledgerWallet,
...metamaskWallet,
...okxWallet,
...onekeyWallet,
...phantomWallet,
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/src/react/swapkit-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,15 @@ export const useSwapKit = () => {

try {
switch (option) {
case WalletOption.METAMASK:
case WalletOption.COINBASE_WEB:
case WalletOption.TRUSTWALLET_WEB:
await swapKit?.connectEVMWallet?.(chains as EVMChain[]);
break;

case WalletOption.METAMASK:
await swapKit?.connectMetamask?.(chains);
break;

case WalletOption.PHANTOM:
await swapKit?.connectPhantom?.(chains);
break;
Expand Down
8 changes: 8 additions & 0 deletions packages/wallets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"@coinbase/wallet-sdk": "~4.3.7",
"@cosmjs/amino": "~0.37.0",
"@cosmjs/proto-signing": "~0.37.0",
"@metamask/connect-evm": "~1.4.0",
"@near-js/transactions": "~2.5.0",
"@near-wallet-selector/bitget-wallet": "~10.1.0",
"@near-wallet-selector/core": "~10.1.0",
Expand Down Expand Up @@ -31,6 +32,7 @@
"@coinbase/wallet-sdk": "4.3.7",
"@cosmjs/amino": "0.37.0",
"@cosmjs/proto-signing": "0.37.0",
"@metamask/connect-evm": "1.4.0",
"@near-js/transactions": "2.5.0",
"@near-wallet-selector/bitget-wallet": "10.1.0",
"@near-wallet-selector/core": "10.1.0",
Expand Down Expand Up @@ -124,6 +126,12 @@
"require": "./dist/src/ledger.cjs",
"types": "./dist/types/ledger.d.ts"
},
"./metamask": {
"bun": "./src/metamask/index.ts",
"default": "./dist/src/metamask/index.js",
"require": "./dist/src/metamask/index.cjs",
"types": "./dist/types/metamask/index.d.ts"
},
"./near-wallet-selector": {
"bun": "./src/near-wallet-selector/index.ts",
"default": "./dist/src/near-wallet-selector/index.js",
Expand Down
68 changes: 68 additions & 0 deletions packages/wallets/src/metamask/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
type Chain,
type EVMChain,
EVMChains,
filterSupportedChains,
getChainConfig,
getRPCUrl,
WalletOption,
} from "@swapkit/helpers";
import { createWallet, getWalletSupportedChains } from "@swapkit/wallet-core";
import { getWeb3WalletMethods } from "@swapkit/wallet-extensions/evm-extensions";
import type { Eip1193Provider } from "ethers";

export type ConnectMetamaskOptions = {
dapp?: { name: string; url?: string; iconUrl?: string };
supportedNetworks?: Record<`0x${string}`, string>;
};

export const metamaskWallet = createWallet({
connect: ({ addChain, supportedChains, walletType }) =>
async function connectMetamask(chains: Chain[], options?: ConnectMetamaskOptions) {
const filteredChains = filterSupportedChains({ chains, supportedChains, walletType });
const { createEVMClient } = await import("@metamask/connect-evm");
const { BrowserProvider } = await import("ethers");

const supportedNetworks =
options?.supportedNetworks ??
(Object.fromEntries(
await Promise.all(
filteredChains.map(async (chain) => [getChainConfig(chain).chainIdHex, await getRPCUrl(chain)] as const),
),
) as Record<`0x${string}`, string>);

const evmClient = await createEVMClient({
api: { supportedNetworks },
dapp: options?.dapp ?? { name: "SwapKit", url: globalThis.location?.href },
});

const chainIds = filteredChains.map((chain) => getChainConfig(chain).chainIdHex as `0x${string}`);
await evmClient.connect({ chainIds });

const eip1193Provider = evmClient.getProvider() as unknown as Eip1193Provider;

await Promise.all(
filteredChains.map(async (chain) => {
const browserProvider = new BrowserProvider(eip1193Provider, "any");
const signer = await browserProvider.getSigner();
const address = await signer.getAddress();

const walletMethods = await getWeb3WalletMethods({
address,
chain,
provider: browserProvider,
walletProvider: eip1193Provider,
});

addChain({ ...walletMethods, address, chain, disconnect: () => evmClient.disconnect(), walletType });
}),
);

return true;
},
name: "connectMetamask",
supportedChains: [...EVMChains] as EVMChain[],
walletType: WalletOption.METAMASK,
});

export const METAMASK_SUPPORTED_CHAINS = getWalletSupportedChains(metamaskWallet);
5 changes: 3 additions & 2 deletions packages/wallets/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { ledgerWallet } from "@swapkit/wallet-hardware/ledger";
import type { trezorWallet } from "@swapkit/wallet-hardware/trezor";
import type { coinbaseWallet } from "./coinbase";
import type { keystoreWallet } from "./keystore";
import type { metamaskWallet } from "./metamask";
import type { walletSelectorWallet } from "./near-wallet-selector";
import type { passkeysWallet } from "./passkeys";
import type { radixWallet } from "./radix";
Expand All @@ -39,7 +40,7 @@ export type SKWallets = {
[WalletOption.LEAP]: typeof keplrWallet;
[WalletOption.LEDGER]: typeof ledgerWallet;
[WalletOption.LEDGER_LIVE]: typeof ledgerWallet;
[WalletOption.METAMASK]: typeof evmWallet;
[WalletOption.METAMASK]: typeof metamaskWallet;
[WalletOption.OKX]: typeof okxWallet;
[WalletOption.OKX_MOBILE]: typeof evmWallet;
[WalletOption.ONEKEY]: typeof onekeyWallet;
Expand Down Expand Up @@ -75,7 +76,7 @@ export type SKWalletsSupportedChains = {
[WalletOption.LEAP]: typeof keplrWallet.connectKeplr.supportedChains;
[WalletOption.LEDGER]: typeof ledgerWallet.connectLedger.supportedChains;
[WalletOption.LEDGER_LIVE]: typeof ledgerWallet.connectLedger.supportedChains;
[WalletOption.METAMASK]: typeof evmWallet.connectEVMWallet.supportedChains;
[WalletOption.METAMASK]: typeof metamaskWallet.connectMetamask.supportedChains;
[WalletOption.OKX]: typeof okxWallet.connectOkx.supportedChains;
[WalletOption.OKX_MOBILE]: typeof evmWallet.connectEVMWallet.supportedChains;
[WalletOption.ONEKEY]: typeof onekeyWallet.connectOnekeyWallet.supportedChains;
Expand Down
2 changes: 1 addition & 1 deletion packages/wallets/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export async function loadWallet<W extends WalletOption>(walletOption: W): Promi
.with(WalletOption.VULTISIG, async () => (await import("@swapkit/wallet-extensions/vultisig")).vultisigWallet)
.with(WalletOption.OKX, async () => (await import("@swapkit/wallet-extensions/okx")).okxWallet)
.with(WalletOption.ONEKEY, async () => (await import("@swapkit/wallet-extensions/onekey")).onekeyWallet)
.with(WalletOption.METAMASK, async () => (await import("./metamask")).metamaskWallet)
.with(WalletOption.EXODUS, async () => (await import("./passkeys")).passkeysWallet)
.with(WalletOption.KEEPKEY, async () => (await import("@swapkit/wallet-hardware/keepkey")).keepkeyWallet)
.with(
Expand All @@ -31,7 +32,6 @@ export async function loadWallet<W extends WalletOption>(walletOption: W): Promi
WalletOption.BRAVE,
WalletOption.COINBASE_WEB,
WalletOption.EIP6963,
WalletOption.METAMASK,
WalletOption.OKX_MOBILE,
WalletOption.TRUSTWALLET_WEB,
async () => (await import("@swapkit/wallet-extensions/evm-extensions")).evmWallet,
Expand Down
3 changes: 3 additions & 0 deletions playgrounds/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
"vite-plugin-node-polyfills": "0.24.0"
},
"devDependencies": {
"@metamask/mobile-wallet-protocol-core": "0.4.0",
"@metamask/mobile-wallet-protocol-dapp-client": "0.3.0",
"@vitejs/plugin-react": "5.1.0",
"eciesjs": "0.4.17",
"rollup-plugin-visualizer": "6.0.5",
"typescript": "5.9.3",
"vite-plugin-top-level-await": "1.6.0",
Expand Down
11 changes: 9 additions & 2 deletions playgrounds/vite/src/WalletPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ export const WalletPicker = ({ skClient, setWallet, setPhrase }: Props) => {
case WalletOption.BITGET:
return skClient.connectBitget?.(chainsToConnect);
case WalletOption.COINBASE_WEB:
case WalletOption.METAMASK:
case WalletOption.TRUSTWALLET_WEB:
case WalletOption.EIP6963:
return skClient.connectEVMWallet(chainsToConnect, option, provider);
case WalletOption.METAMASK:
return skClient.connectMetamask(chainsToConnect);
case WalletOption.TALISMAN:
return skClient.connectTalisman(chainsToConnect);
case WalletOption.KEPLR:
Expand Down Expand Up @@ -252,7 +253,13 @@ export const WalletPicker = ({ skClient, setWallet, setPhrase }: Props) => {
[chains.length, handleConnection],
);

const eip6963Wallets = getEIP6963Wallets().providers;
// MetaMask now connects via the dedicated SDK-backed METAMASK button
// (@metamask/connect-evm), which also handles the installed extension. Drop it
// from the EIP-6963 discovery list to avoid a duplicate, SDK-bypassing entry.
// EIP6963ProviderInfo has no `rdns`, so match on the announced name.
const eip6963Wallets = getEIP6963Wallets().providers.filter(
(wallet) => !/metamask/i.test(wallet.info.name),
);

return (
<div style={{ display: "flex", gap: 12, position: "relative" }}>
Expand Down
14 changes: 14 additions & 0 deletions playgrounds/vite/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ export default defineConfig({

esbuild: { logOverride: { "this-is-undefined-in-esm": "silent" }, target: "es2022" },
optimizeDeps: {
// NOTE: MetaMask's connect SDK renders its install/QR modal via Stencil lazy
// web components (@metamask/multichain-ui) that resolve their chunks from
// import.meta.url. Pre-bundling breaks that, so serve that package as native ESM.
exclude: ["@metamask/multichain-ui"],
// NOTE: connect-multichain dynamically imports these CJS packages with NAMED
// imports (e.g. { SessionStore } from "@metamask/mobile-wallet-protocol-core").
// Without listing them here, Vite emits default-only interop chunks
// (`export default require_dist()`) so the named members are undefined at runtime
// and the mobile/QR (extension-not-installed) flow throws before it can connect.
include: [
"@metamask/mobile-wallet-protocol-core",
"@metamask/mobile-wallet-protocol-dapp-client",
"eciesjs",
],
esbuildOptions: {
// NOTE: Have to be added to fix: Uncaught ReferenceError: global is not defined
define: { global: "globalThis" },
Expand Down
Loading