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

v0.0.0-alpha.9 #17

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

## [Unreleased]

## [[v0.0.0-alpha.8]](https://github.com/multiversx/mx-sdk-dapp-core/pull/16)] - 2024-08-27
- [Added `@multiversx/sdk-web-wallet-cross-window-provider` as peer dep](https://github.com/multiversx/mx-sdk-dapp-core/pull/15)
## [[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)
- [Make middlewares registration more scalable](https://github.com/multiversx/mx-sdk-dapp-core/pull/11)
- [Fix Node Polyfills](https://github.com/multiversx/mx-sdk-dapp-core/pull/10)
- [Removed chain id from network slice & added esbuild and absolute imports](https://github.com/multiversx/mx-sdk-dapp-core/pull/3)
- [Reverted absolute imports](https://github.com/multiversx/mx-sdk-dapp-core/pull/2)
- [Added network store](https://github.com/multiversx/mx-sdk-dapp-core/pull/1)
Expand Down
6 changes: 5 additions & 1 deletion esbuild.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const esbuild = require('esbuild');
const glob = require('glob');
const plugin = require('node-stdlib-browser/helpers/esbuild/plugin');
const stdLibBrowser = require('node-stdlib-browser');
const { nodeExternalsPlugin } = require('esbuild-node-externals');

/*
The reason why we use esbuild instead of tsc is because esbuild can output .mjs files
Expand Down Expand Up @@ -34,7 +37,8 @@ const executeBuild = () =>
global: 'global',
process: 'process',
Buffer: 'Buffer'
}
},
plugins: [plugin(stdLibBrowser), nodeExternalsPlugin()]
})
.then(() => {
console.log(
Expand Down
19 changes: 14 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-dapp-core",
"version": "0.0.0-alpha.8",
"version": "0.0.0-alpha.9",
"main": "out/index.js",
"module": "out/index.js",
"types": "out/index.d.ts",
Expand Down Expand Up @@ -30,16 +30,23 @@
"access": "public"
},
"dependencies": {
"@lifeomic/axios-fetch": "3.0.1",
"@multiversx/sdk-extension-provider": "3.0.0",
"@multiversx/sdk-hw-provider": "6.4.0",
"@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-connect-provider": "4.1.2",
"@multiversx/sdk-web-wallet-provider": "3.2.1",
"@types/lodash": "^4.17.4",
"isomorphic-fetch": "^3.0.0",
"lodash": "^4.17.21",
"zustand": "^4.4.7"
},
"peerDependencies": {
"@multiversx/sdk-core": ">= 13.0.0",
"@multiversx/sdk-dapp-utils": "^0.0.1",
"@multiversx/sdk-web-wallet-cross-window-provider": ">= 0.4.2",
"@multiversx/sdk-dapp-utils": ">= 0.1.0",
"@multiversx/sdk-web-wallet-cross-window-provider": ">= 1.0.0",
"axios": ">=1.6.5",
"bignumber.js": "9.x"
},
Expand All @@ -48,8 +55,8 @@
},
"devDependencies": {
"@multiversx/sdk-core": ">= 13.0.0",
"@multiversx/sdk-dapp-utils": "^0.0.1",
"@multiversx/sdk-web-wallet-cross-window-provider": ">= 0.4.2",
"@multiversx/sdk-dapp-utils": ">= 0.1.0",
"@multiversx/sdk-web-wallet-cross-window-provider": ">= 1.0.0",
"@swc/core": "^1.4.17",
"@swc/jest": "^0.2.36",
"@types/node": "20.12.8",
Expand All @@ -59,6 +66,7 @@
"axios-mock-adapter": "^1.22.0",
"bignumber.js": "9.x",
"esbuild": "^0.21.1",
"esbuild-node-externals": "1.14.0",
"eslint": "9.1.1",
"eslint-config-prettier": "9.1.0",
"eslint-config-standard": "17.1.0",
Expand All @@ -72,6 +80,7 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"msw": "1.3.1",
"node-stdlib-browser": "1.2.0",
"prettier": "3.2.5",
"protobufjs": "^7.3.0",
"react": "^18.3.1",
Expand Down
2 changes: 1 addition & 1 deletion src/__mocks__/accountConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fallbackNetworkConfigurations } from 'constants/network';
import { fallbackNetworkConfigurations } from 'constants/network.constants';
import { EnvironmentsEnum } from 'types';

export const testAddress =
Expand Down
28 changes: 28 additions & 0 deletions src/apiCalls/accounts/getAccountFromApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ACCOUNTS_ENDPOINT } from 'apiCalls/endpoints';
import { axiosInstance } from 'apiCalls/utils/axiosInstance';
import { getCleanApiAddress } from 'apiCalls/utils/getCleanApiAddress';
import { AccountType } from 'types/account.types';

export const accountFetcher = (address: string | null) => {
const apiAddress = getCleanApiAddress();
const url = `${apiAddress}/${ACCOUNTS_ENDPOINT}/${address}?withGuardianInfo=true`;
// we need to get it with an axios instance because of cross-window user interaction issues
return axiosInstance.get(url, {
baseURL: apiAddress
});
};

export const getAccountFromApi = async (address?: string) => {
if (!address) {
return null;
}

try {
const { data } = await accountFetcher(address);
return data as AccountType;
} catch (err) {
console.error('error fetching configuration for ', address);
}

return null;
};
1 change: 1 addition & 0 deletions src/apiCalls/accounts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './getAccountFromApi';
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { networkStore } from '../network';
import { networkSelector } from 'store/selectors/networkSelectors';
import { getState } from 'store/store';

export const getCleanApiAddress = (customApiAddress?: string) => {
const { network } = networkStore.getState();
const network = networkSelector(getState());
const apiAddress = customApiAddress ?? network.apiAddress;
return apiAddress.endsWith('/') ? apiAddress.slice(0, -1) : apiAddress;
};
2 changes: 1 addition & 1 deletion src/apiCalls/configuration/getNetworkConfigFromApi.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';
import { getCleanApiAddress } from 'store/slices/network/actions/getCleanApiAddress';
import { ApiNetworkConfigType } from 'types/network.types';
import { NETWORK_CONFIG_ENDPOINT } from '../endpoints';
import { getCleanApiAddress } from '../utils/getCleanApiAddress';

const urlIsValid = (url: string) => {
try {
Expand Down
4 changes: 4 additions & 0 deletions src/apiCalls/utils/axiosFetcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { axiosInstance } from 'apiCalls/utils/axiosInstance';

export const axiosFetcher = (url: string) =>
axiosInstance.get(url).then((response) => response.data);
99 changes: 99 additions & 0 deletions src/apiCalls/utils/axiosInstance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { buildAxiosFetch } from '@lifeomic/axios-fetch';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';

// Needs to be used beacause an async call made after cross-window user interaction makes the dapp unresponsive

const fetch = buildAxiosFetch(axios);

const getFormattedAxiosResponse = async <T>(response: Response, config?: T) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

// Clone the response to be able to read it twice (for status and data)
const clonedResponse = response.clone();

// Parse the JSON body asynchronously
const jsonPromise = clonedResponse.json();

// Return the standardized response object
const [responseData] = await Promise.all([jsonPromise]);
return {
data: responseData,
status: response.status,
statusText: response.statusText,
headers: response.headers,
config
};
};

async function customPost<T = any, R = AxiosResponse<T, any>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D> | undefined
): Promise<R> {
try {
const response = await fetch(url, {
method: 'POST',
body: data ? JSON.stringify(data) : undefined,
headers: {
'Content-Type': 'application/json',
...(config?.headers || {})
},
...config
} as RequestInit);

return getFormattedAxiosResponse(response, config) as unknown as Promise<R>;
} catch (error) {
console.error('Fetch Error:', error);
throw error;
}
}

async function customGet<T = any, R = AxiosResponse<T, any>, D = any>(
url: string,
config?: AxiosRequestConfig<D> | undefined
): Promise<R> {
try {
const response = await fetch(url, config as RequestInit);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

return getFormattedAxiosResponse(response, config) as unknown as Promise<R>;
} catch (error) {
console.error('Fetch Error:', error);
throw error;
}
}

async function customPatch<T = any, R = AxiosResponse<T, any>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D> | undefined
): Promise<R> {
try {
const response = await fetch(url, {
method: 'PATCH',
body: data ? JSON.stringify(data) : undefined,
headers: config?.headers || {},
...config
} as RequestInit);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

return getFormattedAxiosResponse(response, config) as unknown as Promise<R>;
} catch (error) {
console.error('Fetch Error:', error);
throw error;
}
}

const axiosInstance = axios.create();
axiosInstance.get = customGet;
axiosInstance.post = customPost;
axiosInstance.patch = customPatch;

export { axiosInstance };
8 changes: 8 additions & 0 deletions src/apiCalls/utils/getCleanApiAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { networkSelector } from 'store/selectors/networkSelectors';
import { getState } from 'store/store';

export const getCleanApiAddress = (customApiAddress?: string) => {
const network = networkSelector(getState());
const apiAddress = customApiAddress ?? network.apiAddress;
return apiAddress.endsWith('/') ? apiAddress.slice(0, -1) : apiAddress;
};
18 changes: 18 additions & 0 deletions src/apiCalls/utils/getScamAddressData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import axios from 'axios';
import { ScamInfoType } from 'types/account.types';
import { ACCOUNTS_ENDPOINT } from '../endpoints';
import { networkSelector } from 'store/selectors';
import { getState } from 'store/store';

export async function getScamAddressData(addressToVerify: string) {
const { apiAddress, apiTimeout } = networkSelector(getState());

const { data } = await axios.get<{
scamInfo?: ScamInfoType;
code?: string;
}>(`${apiAddress}/${ACCOUNTS_ENDPOINT}/${addressToVerify}`, {
timeout: Number(apiTimeout)
});

return data;
}
4 changes: 4 additions & 0 deletions src/apiCalls/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './axiosFetcher';
export * from './axiosInstance';
export * from './getCleanApiAddress';
export * from './getScamAddressData';
10 changes: 10 additions & 0 deletions src/constants/browser.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { safeWindow } from './window.constants';

const userAgent = String(safeWindow?.navigator?.userAgent);

export const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);

const isFirefoxOnWindows =
/firefox/i.test(userAgent) && /windows/i.test(userAgent);

export const isBrowserWithPopupConfirmation = isSafari || isFirefoxOnWindows;
13 changes: 13 additions & 0 deletions src/constants/errorMessages.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const ERROR_SIGNING = 'error when signing';
export const CANCELLED = 'cancelled';
export const TRANSACTION_CANCELLED = 'Transaction canceled';
export const ERROR_SIGNING_TX = 'error signing transaction';
export const PROVIDER_NOT_INITIALIZED = 'provider not initialized';
export const MISSING_PROVIDER_MESSAGE =
'You need a signer/valid signer to send a transaction,use either WalletProvider, LedgerProvider or WalletConnect';
export const DEFAULT_TRANSACTION_STATUS_MESSAGE =
'Undefined transaction status';
export const SECOND_LOGIN_ATTEMPT_ERROR =
'Action not allowed. User is logged in. Call logout() first';
export const SENDER_DIFFERENT_THAN_LOGGED_IN_ADDRESS =
'You cannot sign transactions from a different account';
11 changes: 7 additions & 4 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export * from './network';
export * from './placeholders';
export * from './storage';
export * from './window';
export * from './network.constants';
export * from './placeholders.constants';
export * from './storage.constants';
export * from './window.constants';
export * from './browser.constants';
export * from './errorMessages.constants';
export * from './ledger.constants';
1 change: 1 addition & 0 deletions src/constants/ledger.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const LEDGER_CONTRACT_DATA_ENABLED_VALUE = 1;
File renamed without changes.
8 changes: 8 additions & 0 deletions src/constants/placeholders.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Not Applicable
* @value N/A
*/
export const N_A = 'N/A';

export const ZERO = '0';
export const ELLIPSIS = '...';
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createJSONStorage } from 'zustand/middleware';
import { safeWindow } from './window';
import { safeWindow } from './window.constants';

export const persistConfig: {
persistReducersStorageType: 'localStorage' | 'sessionStorage';
Expand Down
File renamed without changes.
Loading
Loading