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

Sign message #18

Merged
merged 11 commits into from
Aug 30, 2024
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- [Added signMessage](https://github.com/multiversx/mx-sdk-dapp-core/pull/18)

## [[0.0.0-alpha.9]](https://github.com/multiversx/mx-sdk-dapp-core)] - 2024-08-29
- [CrossWindow login](https://github.com/multiversx/mx-sdk-dapp-core/pull/13)

## [[v0.0.0-alpha.8]](https://github.com/multiversx/mx-sdk-dapp-core/pull/16) - 2024-08-27
- [Added sdk-web-wallet-cross-window-provider as peer dependency](https://github.com/multiversx/mx-sdk-dapp-core/pull/14)
- [Generic login + ExtensionProvider login](https://github.com/multiversx/mx-sdk-dapp-core/pull/12)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@multiversx/sdk-metamask-provider": "0.0.5",
"@multiversx/sdk-native-auth-client": "^1.0.8",
"@multiversx/sdk-opera-provider": "1.0.0-alpha.1",
"@multiversx/sdk-wallet": "4.5.1",
"@multiversx/sdk-wallet-connect-provider": "4.1.2",
"@multiversx/sdk-web-wallet-provider": "3.2.1",
"@types/lodash": "^4.17.4",
Expand Down
64 changes: 0 additions & 64 deletions src/core/methods/init/init.ts

This file was deleted.

46 changes: 46 additions & 0 deletions src/core/methods/initApp/initApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { initStore } from 'store/store';
import { defaultStorageCallback } from 'store/storage';
import { setNativeAuthConfig } from 'store/actions/config/configActions';
import { initializeNetwork } from 'store/actions';
import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types';
import { getDefaultNativeAuthConfig } from 'services/nativeAuth/methods/getDefaultNativeAuthConfig';
import { InitAppType } from './initApp.types';

const defaultInitAppProps = {
storage: {
getStorageCallback: defaultStorageCallback
}
};

/**
* Initializes the dApp with the given configuration.
* @param props - The configuration for the dApp initialization.
*
* @example
* ```ts
initApp({
nativeAuth: true,
environment: EnvironmentsEnum.devnet
});
* ```
* */
export const initApp = async ({
storage = defaultInitAppProps.storage,
dAppConfig
}: InitAppType) => {
initStore(storage.getStorageCallback);

if (dAppConfig?.nativeAuth) {
const nativeAuthConfig: NativeAuthConfigType =
typeof dAppConfig.nativeAuth === 'boolean'
? getDefaultNativeAuthConfig()
: dAppConfig.nativeAuth;

setNativeAuthConfig(nativeAuthConfig);
}

await initializeNetwork({
customNetworkConfig: dAppConfig.network,
environment: dAppConfig.environment
});
};
48 changes: 48 additions & 0 deletions src/core/methods/initApp/initApp.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { StorageCallback } from 'store/storage';
import { CustomNetworkType } from 'types/network.types';
import { EnvironmentsEnum } from 'types/enums.types';
import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types';

type BaseDappConfigType = {
/**
* The native auth configuration for the dApp.
* If set to `true`, will fallback on default configuration.
* If set to `false`, will disable native auth.
* If set to `NativeAuthConfigType`, will set the native auth configuration.
*/
nativeAuth?: boolean | NativeAuthConfigType;
};

export type EnvironmentDappConfigType = BaseDappConfigType & {
/**
* If passed in, will automatically initialize the network with the given environment.
*/
environment: EnvironmentsEnum;
network?: CustomNetworkType;
};

export type CustomNetworkDappConfigType = BaseDappConfigType & {
/**
* Can override the network configuration, e.g. for sovereign shards.
* Must include `apiAddress` if provided.
*/
network: CustomNetworkType & { apiAddress: string };
environment?: never;
};

export type DappConfigType =
| EnvironmentDappConfigType
| CustomNetworkDappConfigType;

export type InitAppType = {
/**
* The storage configuration for the dApp.
*/
storage?: {
/**
* The callback to get the storage (custom storage).
*/
getStorageCallback: StorageCallback;
};
dAppConfig: DappConfigType;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { setLoginToken } from 'store/actions/loginInfo/loginInfoActions';
import { IProvider } from 'core/providers/types/providerFactory.types';
import { loginAction } from 'store/actions';
import { AccountType } from 'types/account.types';
import { getImpersonatedAccountDetails } from './getImpersonatedAccountDetails';
import { getAccountFromToken } from './getAccountFromToken';
import { getLatestNonce } from 'core/methods/account/getLatestNonce';

export async function impersonateAccount({
export async function extractAccountFromToken({
loginToken,
extraInfoData,
address,
Expand All @@ -20,33 +20,33 @@ export async function impersonateAccount({
address: string;
provider: IProvider;
}) {
const impersonationDetails = await getImpersonatedAccountDetails({
const accountDetails = await getAccountFromToken({
originalLoginToken: loginToken,
extraInfoData,
address
});

if (impersonationDetails.modifiedLoginToken) {
setLoginToken(impersonationDetails.modifiedLoginToken);
if (accountDetails.modifiedLoginToken) {
setLoginToken(accountDetails.modifiedLoginToken);
}

if (impersonationDetails.account) {
if (accountDetails.account) {
loginAction({
address: impersonationDetails.address,
address: accountDetails.address,
providerType: provider.getType()
});

const newAccount: AccountType = {
...impersonationDetails.account,
nonce: getLatestNonce(impersonationDetails.account)
...accountDetails.account,
nonce: getLatestNonce(accountDetails.account)
};

setAccount(newAccount);
return {
...impersonationDetails,
...accountDetails,
account: newAccount
};
}

return impersonationDetails;
return accountDetails;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getAccount } from 'utils/account/getAccount';
import { getModifiedLoginToken } from './getModifiedLoginToken';

interface GetImpersonatedAccountDetailsType {
interface GetAccountFromTokenType {
address: string;
originalLoginToken?: string;
extraInfoData: {
Expand All @@ -10,11 +10,11 @@ interface GetImpersonatedAccountDetailsType {
};
}

export const getImpersonatedAccountDetails = async ({
export const getAccountFromToken = async ({
originalLoginToken,
extraInfoData,
address
}: GetImpersonatedAccountDetailsType) => {
}: GetAccountFromTokenType) => {
const modifiedLoginToken = await getModifiedLoginToken({
loginToken: originalLoginToken,
extraInfoData
Expand Down
35 changes: 7 additions & 28 deletions src/core/methods/login/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types';
import { getIsLoggedIn } from 'core/methods/account/getIsLoggedIn';
import { getAddress } from 'core/methods/account/getAddress';
import { loginAction, logoutAction } from 'store/actions';
import { impersonateAccount } from './helpers/impersonateAccount';
import { extractAccountFromToken } from './helpers/extractAccountFromToken';
import { SECOND_LOGIN_ATTEMPT_ERROR } from 'constants/errorMessages.constants';
import { getCallbackUrl } from './helpers/getCallbackUrl';

Expand All @@ -38,28 +38,6 @@ async function loginWithoutNativeToken(provider: IProvider) {
};
}

async function tryImpersonateAccount({
loginToken,
extraInfoData,
address,
provider
}: {
loginToken: string;
extraInfoData: {
multisig?: string;
impersonate?: string;
};
address: string;
provider: IProvider;
}) {
return await impersonateAccount({
loginToken,
extraInfoData,
address,
provider
});
}

async function loginWithNativeToken(
provider: IProvider,
nativeAuthConfig: NativeAuthConfigType
Expand Down Expand Up @@ -104,12 +82,13 @@ async function loginWithNativeToken(
signature,
nativeAuthToken
});

loginAction({
address,
providerType: provider.getType()
});

const impersonationDetails = await tryImpersonateAccount({
const accountDetails = await extractAccountFromToken({
loginToken,
extraInfoData: {
multisig: loginResult?.multisig,
Expand All @@ -119,19 +98,19 @@ async function loginWithNativeToken(
provider
});

if (impersonationDetails.account) {
setAccount(impersonationDetails.account);
if (accountDetails.account) {
setAccount(accountDetails.account);
} else {
logoutAction();
console.error('Failed to fetch account');
throw new Error('Failed to fetch account');
}

return {
address: impersonationDetails?.address || address,
address: accountDetails?.address || address,
signature,
nativeAuthToken,
loginToken: impersonationDetails?.modifiedLoginToken || loginToken,
loginToken: accountDetails?.modifiedLoginToken || loginToken,
nativeAuthConfig
};
}
Expand Down
8 changes: 8 additions & 0 deletions src/core/methods/signMessage/getVerifier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Address } from '@multiversx/sdk-core/out';
import { UserPublicKey, UserVerifier } from '@multiversx/sdk-wallet';

export const getVerifier = (address: string) => {
const publicKey = new UserPublicKey(Address.fromString(address).pubkey());

return new UserVerifier(publicKey);
};
48 changes: 48 additions & 0 deletions src/core/methods/signMessage/signMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { SignableMessage, Address } from '@multiversx/sdk-core';
import { getAccountProvider } from 'core/providers';
import { getProviderType } from 'core/providers/helpers/utils';
import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider';
import { Nullable } from 'types';
import { getAddress } from '../account/getAddress';
import { addOriginToLocationPath } from 'utils/window/addOriginToLocationPath';
import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types';

export interface SignMessageType {
message: string;
callbackRoute?: string;
options?: {
hasConsentPopup?: boolean;
};
}

// TODO: upgrade to Message
export const signMessage = async ({
message,
callbackRoute,
options
}: SignMessageType): Promise<Nullable<SignableMessage>> => {
const address = getAddress();
const provider = getAccountProvider();
const providerType = getProviderType(provider);

const callbackUrl = addOriginToLocationPath(callbackRoute);
const signableMessage = new SignableMessage({
address: new Address(address),
message: Buffer.from(message, 'ascii')
});

if (
options?.hasConsentPopup &&
providerType === ProviderTypeEnum.crossWindow
) {
(provider as unknown as CrossWindowProvider).setShouldShowConsentPopup(
true
);
}

const signedMessage = await provider.signMessage(signableMessage, {
callbackUrl: encodeURIComponent(callbackUrl)
});

return signedMessage;
};
Loading