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

Update universalWalletConnector to include switchChain method #24

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ bower_components
Thumbs.db

# Ignore built ts files
dist/**/*
# dist/**/*

# ignore yarn.lock
yarn.lock
Expand Down
2 changes: 2 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lib/connectors/dedicatedWalletConnector.js';
export * from './lib/connectors/universalWalletConnector.js';
2 changes: 2 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lib/connectors/dedicatedWalletConnector.js';
export * from './lib/connectors/universalWalletConnector.js';
52 changes: 52 additions & 0 deletions dist/lib/connectors/dedicatedWalletConnector.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { OAuthExtension, OAuthProvider } from '@magic-ext/oauth';
import type { MagicSDKAdditionalConfiguration } from '@magic-sdk/provider';
import { type MagicConnectorParams, type MagicOptions } from './magicConnector.js';
/**
* Dedicated Wallet Connector class used to connect to wallet using Dedicated Wallet.
* It uses modal UI defined in our package which also takes in various styling options
* for custom experience.
*
* @example
* ```typescript
* import { DedicatedWalletConnector } from '@magiclabs/wagmi-connector';
* const connector = new DedicatedWalletConnector({
* options: {
* apiKey: YOUR_MAGIC_LINK_API_KEY, //required
* //...Other options
* },
* });
* ```
* @see https://github.com/magiclabs/wagmi-magic-connector#-usage
* @see https://magic.link/docs/dedicated/overview
*/
interface DedicatedWalletOptions extends MagicOptions {
enableEmailLogin?: boolean;
enableSMSLogin?: boolean;
oauthOptions?: {
providers: OAuthProvider[];
callbackUrl?: string;
};
magicSdkConfiguration?: MagicSDKAdditionalConfiguration<string, OAuthExtension[]>;
}
export interface DedicatedWalletConnectorParams extends MagicConnectorParams {
options: DedicatedWalletOptions;
}
export declare function dedicatedWalletConnector({ chains, options, }: DedicatedWalletConnectorParams): import("@wagmi/core").CreateConnectorFn<unknown, {
id: string;
type: string;
name: string;
getProvider: () => Promise<(import("@magic-sdk/provider/dist/types/modules/rpc-provider").RPCProviderModule & import("web3-core").AbstractProvider) | null>;
connect: () => Promise<{
chainId: number;
accounts: `0x${string}`[];
}>;
disconnect: () => Promise<void>;
getAccounts: () => Promise<`0x${string}`[]>;
getChainId: () => Promise<number>;
isAuthorized: () => Promise<boolean>;
onAccountsChanged: (accounts: string[]) => Promise<void>;
onChainChanged: (chain: string) => void;
onConnect: (connectInfo: import("viem").ProviderConnectInfo) => Promise<void>;
onDisconnect: () => void;
}, {}>;
export {};
150 changes: 150 additions & 0 deletions dist/lib/connectors/dedicatedWalletConnector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { createConnector, normalizeChainId } from '@wagmi/core';
import { magicConnector, } from './magicConnector.js';
import { UserRejectedRequestError, getAddress } from 'viem';
import { createModal } from '../modal/view.js';
export function dedicatedWalletConnector({ chains, options, }) {
let { id, name, type, isModalOpen, getAccount, getMagicSDK, getProvider, onAccountsChanged, } = magicConnector({
chains,
options: { ...options, connectorType: 'dedicated' },
});
const oauthProviders = options.oauthOptions?.providers ?? [];
const oauthCallbackUrl = options.oauthOptions?.callbackUrl;
const enableSMSLogin = options.enableSMSLogin ?? false;
const enableEmailLogin = options.enableEmailLogin ?? true;
/**
* This method is used to get user details from the modal UI
* It first creates the modal UI and then waits for the user to
* fill in the details and submit the form.
*/
const getUserDetailsByForm = async (enableSMSLogin, enableEmailLogin, oauthProviders) => {
const output = (await createModal({
accentColor: options.accentColor,
isDarkMode: options.isDarkMode,
customLogo: options.customLogo,
customHeaderText: options.customHeaderText,
enableSMSLogin: enableSMSLogin,
enableEmailLogin: enableEmailLogin,
oauthProviders,
}));
isModalOpen = false;
return output;
};
return createConnector((config) => ({
id,
type,
name,
getProvider,
connect: async function () {
if (!options.apiKey) {
throw new Error('Magic API Key is not provided.');
}
const provider = await getProvider();
if (provider?.on) {
provider.on('accountsChanged', this.onAccountsChanged.bind(this));
provider.on('chainChanged', this.onChainChanged.bind(this));
provider.on('disconnect', this.onDisconnect.bind(this));
}
let chainId;
try {
chainId = await this.getChainId();
}
catch {
chainId = 0;
}
if (await this.isAuthorized()) {
return {
chainId,
accounts: [await getAccount()],
};
}
if (!isModalOpen) {
const modalOutput = await getUserDetailsByForm(enableSMSLogin, enableEmailLogin, oauthProviders);
const magic = getMagicSDK();
// LOGIN WITH MAGIC USING OAUTH PROVIDER
if (modalOutput.oauthProvider)
await magic.oauth.loginWithRedirect({
provider: modalOutput.oauthProvider,
redirectURI: oauthCallbackUrl ?? window.location.href,
});
// LOGIN WITH MAGIC USING EMAIL
if (modalOutput.email)
await magic.auth.loginWithEmailOTP({
email: modalOutput.email,
});
// LOGIN WITH MAGIC USING PHONE NUMBER
if (modalOutput.phoneNumber)
await magic.auth.loginWithSMS({
phoneNumber: modalOutput.phoneNumber,
});
if (await magic.user.isLoggedIn())
return {
accounts: [await getAccount()],
chainId,
};
}
throw new UserRejectedRequestError(Error('User Rejected Request'));
},
disconnect: async () => {
try {
const magic = getMagicSDK();
await magic?.wallet.disconnect();
config.emitter.emit('disconnect');
}
catch (error) {
console.error('Error disconnecting from Magic SDK:', error);
}
},
getAccounts: async () => {
const provider = await getProvider();
const accounts = (await provider?.request({
method: 'eth_accounts',
}));
return accounts.map((x) => getAddress(x));
},
getChainId: async () => {
const provider = await getProvider();
if (provider) {
const chainId = await provider.request({
method: 'eth_chainId',
params: [],
});
return normalizeChainId(chainId);
}
const networkOptions = options.magicSdkConfiguration?.network;
if (typeof networkOptions === 'object') {
const chainID = networkOptions.chainId;
if (chainID)
return normalizeChainId(chainID);
}
throw new Error('Chain ID is not defined');
},
isAuthorized: async () => {
try {
const magic = getMagicSDK();
if (!magic) {
return false;
}
const isLoggedIn = await magic.user.isLoggedIn();
if (isLoggedIn)
return true;
const result = await magic.oauth.getRedirectResult();
return result !== null;
}
catch { }
return false;
},
onAccountsChanged,
onChainChanged(chain) {
const chainId = normalizeChainId(chain);
config.emitter.emit('change', { chainId });
},
async onConnect(connectInfo) {
const chainId = normalizeChainId(connectInfo.chainId);
const accounts = await this.getAccounts();
config.emitter.emit('connect', { accounts, chainId });
},
onDisconnect: () => {
config.emitter.emit('disconnect');
},
}));
}
Loading