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

feat: replace wcm with appkit, create options mapping function #5564

Draft
wants to merge 28 commits into
base: v2.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e8decc1
feat: replace wcm with appkit, create options mapping function
tomiir Dec 19, 2024
326e1f5
chore: remove viem
tomiir Dec 19, 2024
6539f9c
chore: debugging
tomiir Jan 20, 2025
58360af
chore: update rollup and appkit deps
tomiir Jan 20, 2025
24ecd20
Update with v2.0
tomiir Jan 20, 2025
38d9720
chore: update lock
tomiir Jan 20, 2025
1366d17
chore: update to appkit basic canary 2
tomiir Jan 24, 2025
88acc25
chore: use basic setuop
tomiir Jan 24, 2025
55fecf9
chore: include optionalChains with chains
magiziz Jan 29, 2025
3a45293
chore: update to appkit canary 3
tomiir Jan 30, 2025
04c7da3
chore: update appkit, remove viem
tomiir Jan 30, 2025
2bac726
chore: update lock
tomiir Jan 30, 2025
ba1e8b9
Merge branch 'v2.0' of github.com:WalletConnect/walletconnect-monorep…
tomiir Jan 30, 2025
aed4f5d
chore: update lock
tomiir Jan 30, 2025
8ed165a
chore: type issue
tomiir Jan 30, 2025
44cae9c
chore: update to appkit basic canary 5
tomiir Jan 31, 2025
d3bdbfc
chore: update ak to preview 6
tomiir Feb 4, 2025
55f7da1
chore: set color mix strength to 0
magiziz Feb 5, 2025
d0673d1
chore: open appkit modal before connecting
magiziz Feb 6, 2025
f547225
chore: show error message when error is thrown
magiziz Feb 7, 2025
b01a3b6
chore: remove close call
magiziz Feb 7, 2025
68347c6
Merge pull request #5632 from WalletConnect/chore/optimize-appkit
magiziz Feb 7, 2025
bb839cd
chore: update ak basic canary
tomiir Feb 7, 2025
b893705
chore: add manual control
tomiir Feb 7, 2025
1b0c275
chore: update to appkit core canary 1
tomiir Feb 11, 2025
222ad50
chore: update to ak preview core 2
tomiir Feb 12, 2025
7b443aa
chore: update to 1.7.0 alpha0
tomiir Feb 27, 2025
9559806
Merge branch 'v2.0' of github.com:WalletConnect/walletconnect-monorep…
tomiir Feb 27, 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ npm-debug.log*
lerna-debug.log
*.lerna_backup

# Bundle
**/bundle-stats.html

# Runtime data
pids
*.pid
Expand Down
9 changes: 2 additions & 7 deletions lerna.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
{
"npmClient": "npm",
"packages": [
"packages/*",
"providers/*"
],
"packages": ["packages/*", "providers/*"],
"command": {
"run": {
"ignore": [
"packages/web3wallet"
]
"ignore": ["packages/web3wallet"]
}
},
"version": "2.19.0"
Expand Down
5,039 changes: 345 additions & 4,694 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@
"prettier": "2.7.1",
"rollup": "2.79.2",
"rollup-plugin-esbuild": "4.9.3",
"rollup-plugin-visualizer": "5.14.0",
"sinon": "14.0.0",
"typescript": "4.7.4",
"typescript": "5.3.3",
"vitest": "0.22.1"
}
}
2 changes: 1 addition & 1 deletion providers/ethereum-provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
"prettier": "prettier --check '{src,test}/**/*.{js,ts,jsx,tsx}'"
},
"dependencies": {
"@reown/appkit": "1.7.0-alpha.0",
"@walletconnect/jsonrpc-http-connection": "1.0.8",
"@walletconnect/jsonrpc-provider": "1.0.14",
"@walletconnect/jsonrpc-types": "1.0.4",
"@walletconnect/jsonrpc-utils": "1.0.8",
"@walletconnect/keyvaluestorage": "1.1.1",
"@walletconnect/modal": "2.7.0",
"@walletconnect/sign-client": "2.19.0",
"@walletconnect/types": "2.19.0",
"@walletconnect/universal-provider": "2.19.0",
Expand Down
83 changes: 61 additions & 22 deletions providers/ethereum-provider/src/EthereumProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ export class EthereumProvider implements IEthereumProvider {
}

public async connect(opts?: ConnectOps): Promise<void> {
console.log(">> Provider.connect");
if (!this.signer.client) {
throw new Error("Provider not initialized. Call init() first");
}
Expand All @@ -289,14 +290,19 @@ export class EthereumProvider implements IEthereumProvider {
const session = await new Promise<SessionTypes.Struct | undefined>(
async (resolve, reject) => {
if (this.rpc.showQrModal) {
this.modal?.subscribeModal((state: { open: boolean }) => {
this.modal?.open();

this.modal?.subscribeState((state: { open: boolean }) => {
// the modal was closed so reject the promise
console.log(">> Modal State2", state);
console.log(">> SEssion2", this.signer.session);
if (!state.open && !this.signer.session) {
this.signer.abortPairingAttempt();
reject(new Error("Connection request reset. Please try again."));
}
});
}
console.log(">> Signer.connect", required, optional);
await this.signer
.connect({
namespaces: {
Expand All @@ -312,25 +318,34 @@ export class EthereumProvider implements IEthereumProvider {
pairingTopic: opts?.pairingTopic,
})
.then((session?: SessionTypes.Struct) => {
console.log(">> Signer.then", session);
resolve(session);
})
.catch((error: Error) => {
console.log(">> Signer.catch", error);
this.modal?.showErrorMessage("Unable to connect");
reject(new Error(error.message));
});
},
);

console.log(">> Session", session);
if (!session) return;

const accounts = getAccountsFromNamespaces(session.namespaces, [this.namespace]);
console.log(">> Accounts", this.accounts);
// if no required chains are set, use the approved accounts to fetch chainIds
this.setChainIds(this.rpc.chains.length ? this.rpc.chains : accounts);
console.log(">> ChainId", this.chainId);
this.setAccounts(accounts);
this.events.emit("connect", { chainId: toHexChainId(this.chainId) });
} catch (error) {
console.log(">> Error", error);
this.signer.logger.error(error);
throw error;
} finally {
if (this.modal) this.modal.closeModal();
console.log(">> Closing Modal", this.modal);
this.modal?.close();
}
}

Expand All @@ -350,14 +365,18 @@ export class EthereumProvider implements IEthereumProvider {
const result = await new Promise<AuthTypes.AuthenticateResponseResult>(
async (resolve, reject) => {
if (this.rpc.showQrModal) {
this.modal?.subscribeModal((state: { open: boolean }) => {
this.modal?.open();
this.modal?.subscribeState((state: { open: boolean }) => {
// the modal was closed so reject the promise
console.log(">> Modal State", state);
console.log(">> SEssion", this.signer.session);
if (!state.open && !this.signer.session) {
this.signer.abortPairingAttempt();
reject(new Error("Connection request reset. Please try again."));
}
});
}
console.log(">> Signer.authenticate", params);
await this.signer
.authenticate(
{
Expand All @@ -367,28 +386,39 @@ export class EthereumProvider implements IEthereumProvider {
walletUniversalLink,
)
.then((result: AuthTypes.AuthenticateResponseResult) => {
console.log(">> Signer.authenticate.then", result);
resolve(result);
})
.catch((error: Error) => {
console.log(">> Signer.authenticate.catch", error);
this.modal?.showErrorMessage("Unable to connect");
reject(new Error(error.message));
});
},
);

const session = result.session;
if (session) {
console.log(">> Got Session", session);
const accounts = getAccountsFromNamespaces(session.namespaces, [this.namespace]);

console.log(">> Accounts", this.accounts);
// if no required chains are set, use the approved accounts to fetch chainIds as both contain <namespace>:<chainId>
this.setChainIds(this.rpc.chains.length ? this.rpc.chains : accounts);
this.setAccounts(accounts);
console.log(">> ChainId", this.chainId);
this.events.emit("connect", { chainId: toHexChainId(this.chainId) });
}

console.log(">> Returning Result", result);
return result;
} catch (error) {
console.log(">> Error", error);
this.signer.logger.error(error);
throw error;
} finally {
if (this.modal) this.modal.closeModal();
console.log(">> Closing Modal", this.modal);
this.modal?.close();
}
}

Expand Down Expand Up @@ -472,12 +502,6 @@ export class EthereumProvider implements IEthereumProvider {
);

this.signer.on("display_uri", (uri: string) => {
if (this.rpc.showQrModal) {
// to refresh the QR we have to close the modal and open it again
// until proper API is provided by walletconnect modal
this.modal?.closeModal();
this.modal?.openModal({ uri });
}
this.events.emit("display_uri", uri);
});
}
Expand Down Expand Up @@ -545,8 +569,8 @@ export class EthereumProvider implements IEthereumProvider {
const rpcMap = opts?.rpcMap || this.buildRpcMap(allChains, opts.projectId);
const qrModalOptions = opts?.qrModalOptions || undefined;
return {
chains: requiredChains?.map((chain) => this.formatChainId(chain)),
optionalChains: optionalChains.map((chain) => this.formatChainId(chain)),
chains: requiredChains?.map((chain: number) => this.formatChainId(chain)),
optionalChains: optionalChains.map((chain: number) => this.formatChainId(chain)),
methods: requiredMethods,
events: requiredEvents,
optionalMethods,
Expand Down Expand Up @@ -587,19 +611,33 @@ export class EthereumProvider implements IEthereumProvider {
this.registerEventListeners();
await this.loadPersistedSession();
if (this.rpc.showQrModal) {
let WalletConnectModalClass;
let appKit;
try {
const { WalletConnectModal } = await import("@walletconnect/modal");
WalletConnectModalClass = WalletConnectModal;
} catch {
throw new Error("To use QR modal, please install @walletconnect/modal package");
const { createAppKit } = await import("@reown/appkit/basic");
const { convertWCMToAppKitOptions } = await import("./wcmToAppKit");
const options = convertWCMToAppKitOptions({
...this.rpc.qrModalOptions,
chains: [...new Set([...this.rpc.chains, ...this.rpc.optionalChains])],
metadata: this.rpc.metadata,
projectId: this.rpc.projectId,
});

if (!options.networks.length) {
throw new Error("No networks found for WalletConnect·");
}

appKit = createAppKit({
...options,
universalProvider: this.signer as any,
manualWCControl: true,
});
} catch (e) {
console.error(e);
throw new Error("To use QR modal, please install @reown/appkit package");
}
if (WalletConnectModalClass) {
if (appKit) {
try {
this.modal = new WalletConnectModalClass({
projectId: this.rpc.projectId,
...this.rpc.qrModalOptions,
});
this.modal = appKit;
} catch (e) {
this.signer.logger.error(e);
throw new Error("Could not generate WalletConnectModal Instance");
Expand All @@ -609,6 +647,7 @@ export class EthereumProvider implements IEthereumProvider {
}

protected loadConnectOpts(opts?: ConnectOps) {
console.log(">> LoadConnectOpts", opts);
if (!opts) return;
const { chains, optionalChains, rpcMap } = opts;
if (chains && isValidArray(chains)) {
Expand Down
135 changes: 135 additions & 0 deletions providers/ethereum-provider/src/wcmToAppKit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import type { AppKitOptions, CaipNetwork, CaipNetworkId } from "@reown/appkit";
import type { WalletConnectModalConfig } from "./types";
import { defineChain } from "@reown/appkit/networks";
import type { AppKitNetwork } from "@reown/appkit/networks";
import type { EthereumProviderOptions } from "./EthereumProvider";

function convertThemeVariables(
wcmTheme?: WalletConnectModalConfig["themeVariables"],
): AppKitOptions["themeVariables"] | undefined {
if (!wcmTheme) return undefined;

return {
"--w3m-font-family": wcmTheme["--wcm-font-family"],
"--w3m-accent": wcmTheme["--wcm-accent-color"],
"--w3m-color-mix": wcmTheme["--wcm-background-color"],
"--w3m-z-index": wcmTheme["--wcm-z-index"] ? Number(wcmTheme["--wcm-z-index"]) : undefined,

"--w3m-qr-color": wcmTheme["--wcm-accent-color"],

"--w3m-font-size-master": wcmTheme["--wcm-text-medium-regular-size"],
"--w3m-border-radius-master": wcmTheme["--wcm-container-border-radius"],
"--w3m-color-mix-strength": 0,
};
}

const mapCaipIdToAppKitCaipNetwork = (caipId: CaipNetworkId): CaipNetwork => {
const [namespace, chainId] = caipId.split(":");
const chain = defineChain({
id: chainId,
caipNetworkId: caipId,
chainNamespace: namespace as CaipNetwork["chainNamespace"],
name: "",
nativeCurrency: {
name: "",
symbol: "",
decimals: 8,
},
rpcUrls: {
default: { http: ["https://rpc.walletconnect.org/v1"] },
},
});

return chain as CaipNetwork;
};

export function convertWCMToAppKitOptions(
wcmConfig: WalletConnectModalConfig & { metadata?: EthereumProviderOptions["metadata"] },
): AppKitOptions {
// Convert chains toCaipNetwork format
const networks: CaipNetwork[] = (wcmConfig.chains as CaipNetworkId[])
?.map(mapCaipIdToAppKitCaipNetwork)
.filter(Boolean);

console.log(">> Networks", networks);
// Ensure at least one network is present
if (networks.length === 0) {
throw new Error("At least one chain must be specified");
}

const defaultNetwork = networks.find((network) => network.id === wcmConfig.defaultChain?.id);
const appKitOptions: AppKitOptions = {
projectId: wcmConfig.projectId,
networks: networks as [AppKitNetwork, ...AppKitNetwork[]],
themeMode: wcmConfig.themeMode,
themeVariables: convertThemeVariables(wcmConfig.themeVariables),
chainImages: wcmConfig.chainImages,
connectorImages: wcmConfig.walletImages,
defaultNetwork,
metadata: {
...wcmConfig.metadata,
name: wcmConfig.metadata?.name || "WalletConnect",
description: wcmConfig.metadata?.description || "Connect to WalletConnect-compatible wallets",
url: wcmConfig.metadata?.url || "https://walletconnect.org",
icons: wcmConfig.metadata?.icons || ["https://walletconnect.org/walletconnect-logo.png"],
},
showWallets: true,
// Explorer options mapping
featuredWalletIds:
wcmConfig.explorerRecommendedWalletIds === "NONE"
? []
: Array.isArray(wcmConfig.explorerRecommendedWalletIds)
? wcmConfig.explorerRecommendedWalletIds
: [],

excludeWalletIds:
wcmConfig.explorerExcludedWalletIds === "ALL"
? []
: Array.isArray(wcmConfig.explorerExcludedWalletIds)
? wcmConfig.explorerExcludedWalletIds
: [],

// Additional AppKit-specific options that don't have direct WCM equivalents
enableEIP6963: false, // Disable 6963 by default
enableInjected: false, // Disable injected by default
enableCoinbase: true, // Default to true
enableWalletConnect: true, // Default to true,
features: {
email: false,
socials: false,
},
};

// Add mobile and desktop wallets as custom wallets if provided
if (wcmConfig.mobileWallets?.length || wcmConfig.desktopWallets?.length) {
Copy link
Author

Choose a reason for hiding this comment

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

this is not correct, change

const customWallets = [
...(wcmConfig.mobileWallets || []).map((wallet) => ({
id: wallet.id,
name: wallet.name,
links: wallet.links,
})),
...(wcmConfig.desktopWallets || []).map((wallet) => ({
id: wallet.id,
name: wallet.name,
links: {
native: wallet.links.native,
universal: wallet.links.universal,
},
})),
];

const allWallets = [
...(appKitOptions.featuredWalletIds || []),
...(appKitOptions.excludeWalletIds || []),
];

// Only add a custom wallet if it's not on the other lists
const uniqueCustomWallets = customWallets.filter((wallet) => !allWallets.includes(wallet.id));

if (uniqueCustomWallets.length) {
appKitOptions.customWallets = uniqueCustomWallets;
}
}

return appKitOptions;
}
1 change: 1 addition & 0 deletions providers/ethereum-provider/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": "../../tsconfig.json",
"include": ["./src/**/*"],
"compilerOptions": {
"moduleResolution": "bundler",
"rootDir": "src",
"outDir": "./dist/types",
"emitDeclarationOnly": true
Expand Down
Loading
Loading