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

Generic login + ExtensionProvider login #12

Merged
merged 15 commits into from
Jul 25, 2024
Merged
72 changes: 48 additions & 24 deletions src/core/ProviderFactory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Transaction } from '@multiversx/sdk-core';
import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider';
import { ExtensionProvider } from '@multiversx/sdk-extension-provider';
import type { IDAppProviderBase } from '@multiversx/sdk-dapp-utils';

export interface IProvider {
login: (options?: { token?: string }) => Promise<any>;
export interface IProvider extends IDAppProviderBase {
init: () => Promise<boolean>;
login: (options?: { token?: string }) => Promise<string | boolean>;
relogin?: () => Promise<void>;
logout: () => Promise<boolean>;
CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
signTransactions: (transaction: Transaction[]) => Promise<Transaction[]>;
setAddress: (address: string) => IProvider;
setShouldShowConsentPopup?: (shouldShow: boolean) => void;
getAddress(): string | undefined;
getSignature(): string | undefined;
}
export interface IProviderConfig {
network: {
Expand All @@ -25,18 +29,21 @@ export interface IProviderRecreateFactory extends IProviderFactory {

export enum ProviderTypeEnum {
iframe = 'iframe',
crossWindow = 'crossWindow'
crossWindow = 'crossWindow',
extension = 'extension',
CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
walletConnect = 'walletConnect',
hardware = 'hardware',
opera = 'opera',
metamask = 'metamask',
wallet = 'wallet',
}

export class ProviderFactory {
public static async create({
public async create({
type,
config: {
network: { walletAddress }
},
address
}: IProviderFactory): Promise<IProvider> {
let createdProvider: IProvider;
config,
}: IProviderFactory): Promise<IProvider | undefined> {
let createdProvider: IProvider | undefined = undefined;

switch (type) {
// case ProviderTypeEnum.iframe: {
Expand All @@ -47,36 +54,47 @@ export class ProviderFactory {
// break;
// }

case ProviderTypeEnum.crossWindow: {
const provider = await ProviderFactory.getCrossWindowProvider({
walletAddress
});
case ProviderTypeEnum.extension: {
const provider = await this.getExtensionProvider();
createdProvider = provider as unknown as IProvider;

createdProvider.getAddress = () => {
return provider.account.address;
}

createdProvider.getSignature = () => {
return provider.account.signature;
}

break;
}

default:
const provider = await ProviderFactory.getCrossWindowProvider({
case ProviderTypeEnum.crossWindow: {
const { walletAddress } = config.network;

const provider = await this.getCrossWindowProvider({
walletAddress
});
createdProvider = provider as unknown as IProvider;

break;
}
}

if (address) {
createdProvider.setAddress(address);
default:
break;
}

return createdProvider;
}

public static async reCreate(
config: IProviderRecreateFactory
): Promise<IProvider> {
return await ProviderFactory.create(config);
): Promise<IProvider | undefined> {
const factory = new ProviderFactory();
return await factory.create(config);
}

private static async getCrossWindowProvider({
private async getCrossWindowProvider({
walletAddress
}: Partial<IProviderConfig['network']>) {
// CrossWindowProvider.getInstance().clearInstance();
Expand All @@ -85,4 +103,10 @@ export class ProviderFactory {
provider.setWalletUrl(String(walletAddress));
return provider;
}

private async getExtensionProvider() {
const provider = ExtensionProvider.getInstance();
await provider.init();
return provider;
}
}
25 changes: 25 additions & 0 deletions src/core/methods/login/helpers/resolveLoginMethod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ProviderTypeEnum } from 'core/ProviderFactory';
import { LoginMethodsEnum } from 'types/enums.types';

export function resolveLoginMethod(providerType: ProviderTypeEnum) {
switch (providerType) {
case ProviderTypeEnum.iframe:
return LoginMethodsEnum.extra;
CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
case ProviderTypeEnum.extension:
return LoginMethodsEnum.extension;
case ProviderTypeEnum.crossWindow:
return LoginMethodsEnum.crossWindow;
case ProviderTypeEnum.hardware:
return LoginMethodsEnum.ledger;
case ProviderTypeEnum.metamask:
return LoginMethodsEnum.metamask;
case ProviderTypeEnum.walletConnect:
return LoginMethodsEnum.walletconnectv2;
case ProviderTypeEnum.wallet:
return LoginMethodsEnum.wallet;
case ProviderTypeEnum.opera:
return LoginMethodsEnum.opera;
default:
return LoginMethodsEnum.none;
}
}
60 changes: 60 additions & 0 deletions src/core/methods/login/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { IProviderFactory, ProviderFactory } from 'core/ProviderFactory';
import { NativeAuthConfigType } from 'types/nativeAuth.types';
import { nativeAuth } from 'services/nativeAuth';
import { setAddress } from 'store/actions/account';
import { setLoginMethod, setTokenLogin } from 'store/actions/loginInfo/loginInfoActions';
import { resolveLoginMethod } from './helpers/resolveLoginMethod';
import { setAccountProvider } from '../../providers/accountProvider';

export const login = async (config: IProviderFactory, nativeAuthConfig?: NativeAuthConfigType) => {
CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
const factory = new ProviderFactory();
const provider = await factory.create(config);

if(!provider) {
throw new Error('Provider not found');
}

await provider.init?.();

const nativeAuthClient = nativeAuth(nativeAuthConfig);

const loginToken = await nativeAuthClient.initialize({
noCache: true
});
await provider.login({ token: loginToken });

const address = provider.getAddress?.();
const signature = provider.getSignature?.();

if(!address) {
throw new Error('Address not found');
}

if(!signature) {
throw new Error('Signature not found');
}

const nativeAuthToken = nativeAuthClient.getToken({
address,
token: loginToken,
signature
});

setAccountProvider(provider);
setAddress(address);
setTokenLogin({
loginToken,
signature,
nativeAuthToken,
nativeAuthConfig
});
setLoginMethod(resolveLoginMethod(config.type))

return {
address,
signature,
nativeAuthToken,
loginToken,
nativeAuthConfig
}
}
2 changes: 1 addition & 1 deletion src/core/methods/login/webWalletLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const webWalletLogin = async ({

return newAccount;
} catch (error) {
console.error('error loging in', error);
console.error('error logging in', error);
throw error;
}
};
8 changes: 4 additions & 4 deletions src/core/providers/accountProvider.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { IDappProvider } from 'types/dappProvider.types';
import { emptyProvider } from './helpers/emptyProvider';
import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider';
import { IProvider } from 'core/ProviderFactory';

export type ProvidersType = IDappProvider | CrossWindowProvider;
export type ProvidersType = IProvider | CrossWindowProvider;

CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
let accountProvider: ProvidersType = emptyProvider;

Expand All @@ -12,6 +12,6 @@ export function setAccountProvider<TProvider extends ProvidersType>(
accountProvider = provider;
}

export function getAccountProvider(): IDappProvider {
return (accountProvider as IDappProvider) || emptyProvider;
export function getAccountProvider(): IProvider {
return (accountProvider as IProvider) || emptyProvider;
}
29 changes: 18 additions & 11 deletions src/core/providers/helpers/emptyProvider.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { SignableMessage, Transaction } from '@multiversx/sdk-core';
import { IDappProvider } from 'types';
import { EngineTypes } from 'utils/walletconnect/__sdkWalletconnectProvider';
import { IProvider } from 'core/ProviderFactory';

export const DAPP_INIT_ROUTE = '/dapp/init';

const notInitializedError = (caller: string) => {
return `Unable to perform ${caller}, Provider not initialized`;
};

export class EmptyProvider implements IDappProvider {
export class EmptyProvider implements IProvider {
init(): Promise<boolean> {
return Promise.resolve(false);
}
Expand All @@ -25,10 +25,6 @@ export class EmptyProvider implements IDappProvider {
throw new Error(notInitializedError(`logout with options: ${options}`));
}

getAddress(): Promise<string> {
throw new Error(notInitializedError('getAddress'));
}

isInitialized(): boolean {
return false;
}
Expand Down Expand Up @@ -59,13 +55,12 @@ export class EmptyProvider implements IDappProvider {
);
}

signTransactions<TOptions = { callbackUrl?: string }, TResponse = []>(
transactions: [],
options?: TOptions
): Promise<TResponse> {
signTransactions<T>(
transactions: T[]
): Promise<T[]> {
throw new Error(
notInitializedError(
`signTransactions with transactions: ${transactions} options: ${options}`
`signTransactions with transactions: ${transactions}`
)
);
}
Expand Down Expand Up @@ -106,6 +101,18 @@ export class EmptyProvider implements IDappProvider {
ping?(): Promise<boolean> {
CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
return Promise.resolve(false);
}

setAddress(address: string): IProvider {
CiprianDraghici marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(notInitializedError(`setAddress with address: ${address}`));
}

getAddress(): string | undefined {
throw new Error(notInitializedError('getAddress'));
}

getSignature(): string | undefined {
throw new Error(notInitializedError(`getSignature`));
}
}

export const emptyProvider = new EmptyProvider();
32 changes: 0 additions & 32 deletions src/types/dappProvider.types.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './enums.types';
export * from './network.types';
export * from './misc.types';
export * from './dappProvider.types';
export * from './misc.types';
Loading