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

3.1.9 #1362

Merged
merged 10 commits into from
Jan 17, 2025
Merged

3.1.9 #1362

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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [[v3.1.9](https://github.com/multiversx/mx-sdk-dapp/pull/1360)] - 2025-01-17

- [Fix useTransactionsTracker export](https://github.com/multiversx/mx-sdk-dapp/pull/1363)
- [Added multiversxWallet](https://github.com/multiversx/mx-sdk-dapp/pull/1361)
- [Added ability to close transaction toasts on timeout](https://github.com/multiversx/mx-sdk-dapp/pull/1352)

## [[v3.1.8](https://github.com/multiversx/mx-sdk-dapp/pull/1360)] - 2025-01-15

- [Added search tooltip to the Ledger address table pagination](https://github.com/multiversx/mx-sdk-dapp/pull/1359)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-dapp",
"version": "3.1.8",
"version": "3.1.9",
"description": "A library to hold the main logic for a dapp on the MultiversX blockchain",
"author": "MultiversX",
"license": "GPL-3.0-or-later",
Expand Down Expand Up @@ -160,7 +160,7 @@
"@lifeomic/axios-fetch": "3.0.1",
"@metamask/providers": "16.0.0",
"@multiversx/sdk-dapp-utils": "1.0.0",
"@multiversx/sdk-extension-provider": "4.0.0",
"@multiversx/sdk-extension-provider": "4.0.1",
"@multiversx/sdk-hw-provider": "7.0.0",
"@multiversx/sdk-metamask-provider": "1.0.0",
"@multiversx/sdk-native-auth-client": "1.0.9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const useTransactionToast = ({
const transactionDisplayInfo = useGetTransactionDisplayInfo(toastId);
const accountShard = useSelector(shardSelector);
const { address } = useGetAccount();
const timeoutRef = useRef<NodeJS.Timeout>();
const lifetimeAfterSuccessTimeoutRef = useRef<NodeJS.Timeout>();
const areSameShardTransactions = useMemo(
() => getAreTransactionsOnSameShard(transactions, accountShard),
[transactions, accountShard]
Expand Down Expand Up @@ -85,21 +85,25 @@ export const useTransactionToast = ({
};

useEffect(() => {
if (!isCompleted || !lifetimeAfterSuccess || timeoutRef.current) {
if (
!isCompleted ||
!lifetimeAfterSuccess ||
lifetimeAfterSuccessTimeoutRef.current
) {
return;
}

timeoutRef.current = setTimeout(() => {
lifetimeAfterSuccessTimeoutRef.current = setTimeout(() => {
handleDeleteToast();
}, lifetimeAfterSuccess);

return () => {
if (timeoutRef.current) {
if (lifetimeAfterSuccessTimeoutRef.current) {
// Clear timer on unmount and also delete the toast
// The toast may have been removed before the timer finished by the re-rendering
// of the toasts list during another toast removal from the store
handleDeleteToast();
clearTimeout(timeoutRef.current);
clearTimeout(lifetimeAfterSuccessTimeoutRef.current);
}
};
}, [lifetimeAfterSuccess, isCompleted]);
Expand Down
2 changes: 1 addition & 1 deletion src/components/TransactionsTracker/TransactionTracker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useBatchTransactionsTracker } from 'hooks/transactions/batch/tracker/useBatchTransactionsTracker';
import { useTransactionsTracker } from 'hooks/transactions/useTransactionsTracker';
import { useTransactionsTracker } from 'hooks/transactions/useTransactionsTracker/useTransactionsTracker';
import { TransactionsTrackerType } from 'types/transactionsTracker.types';

export function TransactionsTracker(props: TransactionsTrackerType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { useCallback, useEffect, useRef } from 'react';
import { TRANSACTIONS_STATUS_DROP_INTERVAL_MS } from 'constants/transactionStatus';
import {
TRANSACTIONS_STATUS_DROP_INTERVAL_MS,
TRANSACTIONS_STATUS_POLLING_INTERVAL_MS
} from 'constants/transactionStatus';
import { removeBatchTransactions } from 'services/transactions';
import { getTransactionsStatus } from 'utils/transactions/batch/getTransactionsStatus';
import { sequentialToFlatArray } from 'utils/transactions/batch/sequentialToFlatArray';
import {
websocketConnection,
WebsocketConnectionStatusEnum
} from '../../../websocketListener/websocketConnection';
import { extractSessionId } from '../../helpers/extractSessionId';
import { timestampIsOlderThan } from '../../helpers/timestampIsOlderThan';
import { useGetPollingInterval } from '../../useGetPollingInterval';
import { useUpdateTrackedTransactions } from '../../useTransactionsTracker/useUpdateTrackedTransactions';
import { useGetBatches } from '../useGetBatches';
import { useUpdateBatch } from './useUpdateBatch';

/**
* Fallback mechanism to check hanging batches
Expand All @@ -22,11 +20,8 @@ export const useCheckHangingBatchesFallback = (props?: {
onFail?: (sessionId: string | null, errorMessage?: string) => void;
}) => {
const { batchTransactionsArray } = useGetBatches();
const pollingInterval = useGetPollingInterval();
const updateBatch = useUpdateBatch();
const updateBatch = useUpdateTrackedTransactions();
const pollingIntervalTimer = useRef<NodeJS.Timeout | null>(null);
const isWebsocketCompleted =
websocketConnection.status === WebsocketConnectionStatusEnum.COMPLETED;
const onSuccess = props?.onSuccess;
const onFail = props?.onFail;

Expand Down Expand Up @@ -73,22 +68,13 @@ export const useCheckHangingBatchesFallback = (props?: {
}, [batchTransactionsArray, updateBatch, onSuccess, onFail]);

useEffect(() => {
if (isWebsocketCompleted) {
// Do not setInterval if we already subscribe to websocket event
if (pollingIntervalTimer.current) {
clearInterval(pollingIntervalTimer.current);
}

return;
}

if (pollingIntervalTimer.current) {
return;
}

pollingIntervalTimer.current = setInterval(() => {
checkHangingBatches();
}, pollingInterval);
}, TRANSACTIONS_STATUS_POLLING_INTERVAL_MS);

return () => {
if (pollingIntervalTimer.current) {
Expand Down
6 changes: 3 additions & 3 deletions src/hooks/transactions/batch/tracker/useVerifyBatchStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { extractSessionId } from 'hooks/transactions/helpers/extractSessionId';
import { useGetSignedTransactions } from 'hooks/transactions/useGetSignedTransactions';
import { useDispatch } from 'reduxStore/DappProviderContext';
import { getTransactionsStatus } from 'utils/transactions/batch/getTransactionsStatus';
import { useUpdateTrackedTransactions } from '../../useTransactionsTracker/useUpdateTrackedTransactions';
import { useCheckBatch } from './useCheckBatch';
import { useUpdateBatch } from './useUpdateBatch';

export const useVerifyBatchStatus = (props?: {
onSuccess?: (sessionId: string | null) => void;
Expand All @@ -15,7 +15,7 @@ export const useVerifyBatchStatus = (props?: {
const { signedTransactions } = useGetSignedTransactions();

const checkBatch = useCheckBatch();
const updateBatch = useUpdateBatch();
const updateBatch = useUpdateTrackedTransactions();
const resolveBatchStatusResponse = useResolveBatchStatusResponse();

const onSuccess = props?.onSuccess;
Expand Down Expand Up @@ -56,7 +56,7 @@ export const useVerifyBatchStatus = (props?: {
const data = await checkBatch({ batchId });
await updateBatch({
sessionId: sessionId.toString(),
isBatchFailed: data?.isBatchFailed,
isFailed: data?.isBatchFailed,
shouldRefreshBalance: true,
transactions: sessionTransactions
});
Expand Down
1 change: 1 addition & 0 deletions src/hooks/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './useSignTransactionsCommonData';
export * from './useSignTransactionsWithDevice';
export * from './useSignTransactionsWithLedger';
export * from './useTrackTransactionStatus';
export * from './useTransactionsTracker';
1 change: 1 addition & 0 deletions src/hooks/transactions/useTrackTransactionStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface UseTrackTransactionStatusArgsType {
onCancelled?: (transactionId: string | null) => void;
}

// TODO: Seems unused and replaced by useCheckTransactionStatus
export function useTrackTransactionStatus({
transactionId: txId,
onSuccess,
Expand Down
1 change: 1 addition & 0 deletions src/hooks/transactions/useTransactionsTracker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useTransactionsTracker';
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useEffect, useRef } from 'react';
import { getTransactionsByHashes as defaultGetTxByHash } from 'apiCalls/transactions';
import { TRANSACTIONS_STATUS_POLLING_INTERVAL_MS } from 'constants/transactionStatus';
import { TransactionsTrackerType } from 'types/transactionsTracker.types';
import { timestampIsOlderThan } from '../helpers/timestampIsOlderThan';
import { useGetPendingTransactions } from '../useGetPendingTransactions';
import { useCheckTransactionStatus } from '../useCheckTransactionStatus';

/**
* Fallback mechanism to check hanging transactions
* Resolves the toast and set the status to failed for each transaction after a certain time (90 seconds)
* */
export const useCheckHangingTransactionsFallback = (
props?: TransactionsTrackerType
) => {
const { pendingTransactionsArray } = useGetPendingTransactions();
const checkTransactionStatus = useCheckTransactionStatus();
const pollingIntervalTimer = useRef<NodeJS.Timeout | null>(null);

const getTransactionsByHash =
props?.getTransactionsByHash ?? defaultGetTxByHash;

const checkHangingTransactions = async () => {
for (const [sessionId] of pendingTransactionsArray) {
if (
!timestampIsOlderThan(
Number(sessionId),
TRANSACTIONS_STATUS_POLLING_INTERVAL_MS
)
) {
continue;
}

await checkTransactionStatus({
getTransactionsByHash,
...props
});
}
};

useEffect(() => {
if (pollingIntervalTimer.current) {
return;
}

pollingIntervalTimer.current = setInterval(() => {
checkHangingTransactions();
}, TRANSACTIONS_STATUS_POLLING_INTERVAL_MS);

return () => {
if (pollingIntervalTimer.current) {
clearInterval(pollingIntervalTimer.current);
}
};
}, []);
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useEffect, useRef } from 'react';
import { getTransactionsByHashes as defaultGetTxByHash } from 'apiCalls/transactions';
import { TransactionsTrackerType } from 'types/transactionsTracker.types';
import { useRegisterWebsocketListener } from '../websocketListener';
import {
websocketConnection,
WebsocketConnectionStatusEnum
} from '../websocketListener/websocketConnection';
import { useCheckTransactionStatus } from './useCheckTransactionStatus';
import { useGetPollingInterval } from './useGetPollingInterval';

export function useTransactionsTracker(props?: TransactionsTrackerType) {
} from '../../websocketListener/websocketConnection';
import { useGetPollingInterval } from '../useGetPollingInterval';
import { useCheckTransactionStatus } from '../useCheckTransactionStatus';

/**
* Fallback mechanism to check the transaction in case of ws connection failure
* Resolves the toast by checking the transaction after a certain time (90seconds)
* */
export const useCheckTransactionOnWsFailureFallback = (
props?: TransactionsTrackerType
) => {
const checkTransactionStatus = useCheckTransactionStatus();
const pollingInterval = useGetPollingInterval();
const pollingIntervalTimer = useRef<NodeJS.Timeout | null>(null);
Expand All @@ -19,15 +24,6 @@ export function useTransactionsTracker(props?: TransactionsTrackerType) {
const getTransactionsByHash =
props?.getTransactionsByHash ?? defaultGetTxByHash;

const onMessage = () => {
checkTransactionStatus({
getTransactionsByHash,
...props
});
};

useRegisterWebsocketListener(onMessage);

useEffect(() => {
if (isWebsocketCompleted) {
// Do not setInterval if we already subscribe to websocket event
Expand All @@ -42,12 +38,17 @@ export function useTransactionsTracker(props?: TransactionsTrackerType) {
return;
}

pollingIntervalTimer.current = setInterval(onMessage, pollingInterval);
pollingIntervalTimer.current = setInterval(() => {
checkTransactionStatus({
getTransactionsByHash,
...props
});
}, pollingInterval);

return () => {
if (pollingIntervalTimer.current) {
clearInterval(pollingIntervalTimer.current);
}
};
}, [onMessage, websocketConnection]);
}
}, [checkTransactionStatus]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect } from 'react';
import { getTransactionsByHashes as defaultGetTxByHash } from 'apiCalls/transactions';
import { TransactionsTrackerType } from 'types/transactionsTracker.types';
import { useRegisterWebsocketListener } from '../../websocketListener';
import { useCheckTransactionStatus } from '../useCheckTransactionStatus';
import { useCheckHangingTransactionsFallback } from './useCheckHangingTransactionsFallback';
import { useCheckTransactionOnWsFailureFallback } from './useCheckTransactionOnWsFailureFallback';

export function useTransactionsTracker(props?: TransactionsTrackerType) {
const checkTransactionStatus = useCheckTransactionStatus();

const getTransactionsByHash =
props?.getTransactionsByHash ?? defaultGetTxByHash;

const onMessage = () => {
checkTransactionStatus({
getTransactionsByHash,
...props
});
};

// register ws listener
useRegisterWebsocketListener(onMessage);

// Fallbacks
useCheckTransactionOnWsFailureFallback(props);

useCheckHangingTransactionsFallback(props);

useEffect(() => {
onMessage();
}, []);
}
Loading
Loading