Skip to content

Commit

Permalink
Create provider (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
arhtudormorar authored Dec 5, 2024
1 parent 7f8ed37 commit 660fb1c
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 101 deletions.
12 changes: 11 additions & 1 deletion src/core/methods/initApp/initApp.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { safeWindow } from 'constants/index';
import { restoreProvider } from 'core/providers/helpers/restoreProvider';
import { ProviderFactory } from 'core/providers/ProviderFactory';
import { getDefaultNativeAuthConfig } from 'services/nativeAuth/methods/getDefaultNativeAuthConfig';
import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types';
import { initializeNetwork } from 'store/actions';
Expand Down Expand Up @@ -30,7 +32,8 @@ const defaultInitAppProps = {
* */
export async function initApp({
storage = defaultInitAppProps.storage,
dAppConfig
dAppConfig,
customProviders
}: InitAppType) {
initStore(storage.getStorageCallback);

Expand All @@ -57,6 +60,13 @@ export async function initApp({

const isLoggedIn = getIsLoggedIn();

const usedProviders = [
...((safeWindow as any)?.multiversx?.providers || []),
...(customProviders || [])
];

ProviderFactory.customProviders(usedProviders || []);

if (isLoggedIn) {
await restoreProvider();
await registerWebsocketListener();
Expand Down
2 changes: 2 additions & 0 deletions src/core/methods/initApp/initApp.types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ICustomProvider } from 'core/providers/types/providerFactory.types';
import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types';
import { StorageCallback } from 'store/storage';
import { EnvironmentsEnum } from 'types/enums.types';
Expand Down Expand Up @@ -49,4 +50,5 @@ export type InitAppType = {
getStorageCallback: StorageCallback;
};
dAppConfig: DappConfigType;
customProviders?: ICustomProvider[];
};
4 changes: 1 addition & 3 deletions src/core/providers/DappProvider/helpers/logout/logout.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getAddress } from 'core/methods/account/getAddress';
import { getProviderType } from 'core/providers/helpers/utils';
import {
IProvider,
ProviderTypeEnum
Expand Down Expand Up @@ -48,7 +47,6 @@ export async function logout({
}
}: IProviderLogout) {
let address = getAddress();
const providerType = getProviderType(provider);

if (options.shouldBroadcastLogoutAcrossTabs) {
broadcastLogoutAcrossTabs(address);
Expand All @@ -59,7 +57,7 @@ export async function logout({

if (
options.hasConsentPopup &&
providerType === ProviderTypeEnum.crossWindow
provider.getType() === ProviderTypeEnum.crossWindow
) {
(provider as unknown as CrossWindowProvider).setShouldShowConsentPopup(
true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Message, Address } from '@multiversx/sdk-core';
import { getAddress } from 'core/methods/account/getAddress';
import { getProviderType } from 'core/providers/helpers/utils';
import {
IProvider,
ProviderTypeEnum
Expand All @@ -22,7 +21,6 @@ export async function signMessage({
options
}: SignMessageType): Promise<Nullable<Message>> {
const address = getAddress();
const providerType = getProviderType(provider);

const messageToSign = new Message({
address: new Address(address),
Expand All @@ -31,7 +29,7 @@ export async function signMessage({

if (
options?.hasConsentPopup &&
providerType === ProviderTypeEnum.crossWindow
provider.getType() === ProviderTypeEnum.crossWindow
) {
(provider as unknown as CrossWindowProvider).setShouldShowConsentPopup(
true
Expand Down
37 changes: 20 additions & 17 deletions src/core/providers/ProviderFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,26 @@ import { getConfig } from './helpers/getConfig';
import { createIframeProvider } from './helpers/iframe/createIframeProvider';
import { createLedgerProvider } from './helpers/ledger/createLedgerProvider';
import {
ICustomProvider,
IProvider,
IProviderFactory,
ProviderTypeEnum
} from './types/providerFactory.types';

export class ProviderFactory {
public async create({
private static _customProviders: ICustomProvider[] = [];

public static customProviders(providers: ICustomProvider[]) {
this._customProviders = providers;
}

public static async create({
type,
config: userConfig,
customProvider
config: userConfig
}: IProviderFactory): Promise<DappProvider> {
let createdProvider: IProvider | null = null;
const { account, ui } = await getConfig(userConfig);
const config = await getConfig(userConfig);
const { account, UI } = config;

switch (type) {
case ProviderTypeEnum.extension: {
Expand All @@ -47,10 +54,7 @@ export class ProviderFactory {
}

case ProviderTypeEnum.ledger: {
const ledgerProvider = await createLedgerProvider(
ui.ledger.eventBus,
ui.ledger.mount
);
const ledgerProvider = await createLedgerProvider(UI.ledger.mount);

if (!ledgerProvider) {
throw new Error('Unable to create ledger provider');
Expand Down Expand Up @@ -106,16 +110,15 @@ export class ProviderFactory {
break;
}

case ProviderTypeEnum.custom: {
if (!customProvider) {
throw new Error('Unable to create custom provider provider');
}
createdProvider = customProvider;
default: {
this._customProviders.forEach(async (customProvider) => {
if (customProvider.type === type) {
createdProvider = await customProvider.constructor(config);
createdProvider.getType = () => type;
}
});
break;
}

default:
break;
}

if (!createdProvider) {
Expand All @@ -125,7 +128,7 @@ export class ProviderFactory {
const dappProvider = new DappProvider(createdProvider);

setAccountProvider(dappProvider);
setProviderType(type);
setProviderType(type as ProviderTypeEnum);

return dappProvider;
}
Expand Down
42 changes: 26 additions & 16 deletions src/core/providers/helpers/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,46 @@ import { defineCustomElements } from '@multiversx/sdk-dapp-core-ui/loader';
import { safeWindow } from 'constants/index';
import {
IProviderConfig,
IProviderConfigUI,
ProviderTypeEnum
} from '../types/providerFactory.types';

export const getConfig = async (config: IProviderConfig = {}) => {
if (!safeWindow.document) {
return config;
const UI: IProviderConfigUI = {
[ProviderTypeEnum.ledger]: {
mount: () => {
throw new Error('mount not implemented');
}
}
};

const defaultConfig = { UI };

defineCustomElements(safeWindow);
const ledgerModalElement = document.createElement(
'ledger-connect-modal'
) as LedgerConnectModal;
document.body.appendChild(ledgerModalElement);
await customElements.whenDefined('ledger-connect-modal');
const eventBus = await ledgerModalElement.getEventBus();
export const getConfig = async (config: IProviderConfig = defaultConfig) => {
if (!safeWindow.document) {
return { ...defaultConfig, ...config };
}

const ui = {
const UI = {
[ProviderTypeEnum.ledger]: {
eventBus,
mount: () => {
mount: async () => {
defineCustomElements(safeWindow);
const ledgerModalElement = document.createElement(
'ledger-connect-modal'
) as LedgerConnectModal;

document.body.appendChild(ledgerModalElement);

const eventBus = await ledgerModalElement.getEventBus();
return eventBus;
}
}
};

return {
...config,
ui: {
...ui,
...config.ui
UI: {
...defaultConfig.UI,
...UI
}
};
};
14 changes: 7 additions & 7 deletions src/core/providers/helpers/ledger/createLedgerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ import { ILedgerAccount } from './ledger.types';
const failInitializeErrorText = 'Check if the MultiversX App is open on Ledger';

export async function createLedgerProvider(
eventBus: IEventBus,
mount: () => void
mount: () => Promise<IEventBus>
): Promise<IProvider | null> {
if (!eventBus) {
throw new Error('Event bus not provided for Ledger provider');
}

const shouldInitiateLogin = !getIsLoggedIn();

let eventBus: IEventBus | undefined;
if (shouldInitiateLogin) {
mount?.();
eventBus = await mount?.();
}

if (!eventBus) {
throw new Error('Event bus not provided for Ledger provider');
}

const manager = LedgerConnectStateManager.getInstance(eventBus);
Expand Down
4 changes: 1 addition & 3 deletions src/core/providers/helpers/restoreProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ export async function restoreProvider() {
}
};

const factory = new ProviderFactory();

const provider = await factory.create({
const provider = await ProviderFactory.create({
type,
config
});
Expand Down
33 changes: 0 additions & 33 deletions src/core/providers/helpers/utils.ts

This file was deleted.

36 changes: 23 additions & 13 deletions src/core/providers/types/providerFactory.types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { IDAppProviderBase } from '@multiversx/sdk-dapp-utils';

// @ts-ignore
export interface IProvider extends IDAppProviderBase {
export interface IProvider<T extends ProviderTypeEnum = ProviderTypeEnum>
extends IDAppProviderBase {
init: () => Promise<boolean>;
login: (options?: { callbackUrl?: string; token?: string }) => Promise<{
address: string;
Expand All @@ -12,7 +13,7 @@ export interface IProvider extends IDAppProviderBase {
}>;
logout: () => Promise<boolean>;
setShouldShowConsentPopup?: (shouldShow: boolean) => void;
getType: () => ProviderTypeEnum;
getType: () => T[keyof T] | string;
getAddress(): Promise<string | undefined>;
// TODO will be removed as soon as the new login method is implemented in the same way for all providers
getTokenLoginSignature(): string | undefined;
Expand All @@ -26,16 +27,17 @@ export interface IEventBus {
unsubscribe(event: string, callback: Function): void;
}

export interface IProviderConfigUI {
ledger: {
mount: () => Promise<IEventBus>;
};
}

export interface IProviderConfig {
account?: {
address: string;
};
ui?: {
ledger: {
eventBus: IEventBus;
mount: () => void;
};
};
UI?: IProviderConfigUI;
}

export enum ProviderTypeEnum {
Expand All @@ -47,13 +49,21 @@ export enum ProviderTypeEnum {
opera = 'opera',
metamask = 'metamask',
passkey = 'passkey',
webhook = 'webhook',
custom = 'custom',
none = ''
}

export interface IProviderFactory {
type: ProviderTypeEnum;
export interface IProviderFactory<
T extends ProviderTypeEnum = ProviderTypeEnum
> {
type: T[keyof T];
config?: IProviderConfig;
customProvider?: IProvider;
}

export interface ICustomProvider<
T extends ProviderTypeEnum = ProviderTypeEnum
> {
name: string;
type: T[keyof T];
icon: string;
constructor: (config: IProviderConfig) => Promise<IProvider>;
}
4 changes: 3 additions & 1 deletion src/store/actions/loginInfo/loginInfoActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
import { getStore } from 'store/store';
import { TokenLoginType } from 'types/login.types';

export const setProviderType = (providerType: ProviderTypeEnum) =>
export const setProviderType = <T extends ProviderTypeEnum = ProviderTypeEnum>(
providerType: T
) =>
getStore().setState(({ loginInfo: state }) => {
state.providerType = providerType;
});
Expand Down
6 changes: 4 additions & 2 deletions src/store/actions/sharedActions/sharedActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { resetStore } from 'store/middleware/logoutMiddleware';
import { getStore } from '../../store';

export const logoutAction = () => getStore().setState(resetStore);
export interface LoginActionPayloadType {
export interface LoginActionPayloadType<
T extends ProviderTypeEnum = ProviderTypeEnum
> {
address: string;
providerType: ProviderTypeEnum;
providerType: T[keyof T];
}

export const loginAction = ({
Expand Down
Loading

0 comments on commit 660fb1c

Please sign in to comment.