diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 00000000..dfe844be --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,173 @@ +# @multiversx/template-dapp + +Migrating your application to `sdk-dapp@5.x` will probably require more code removal than insertion. Of course, each application is different, so this guide will have a generic character, pointing out the main areas where you might need to change your code. +The main areas that might need code restructuring are: + +- package.json library dependencies +- index.tsx file where the app bootstraps +- App.tsx, the main file of your application +- logging in and out +- sending and signing transactions +- component imports related to displaying data +- types + +A typical migration can be seen in this [pull request](https://github.com/multiversx/mx-template-dapp/pull/343). + +Next, we will make a brief overview of the main changes required. + +## 1. Changes in [`package.json`](https://github.com/multiversx/mx-template-dapp/pull/343/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519) + +#### Dependencies + + +- Updated: + - `@multiversx/sdk-dapp` (version `^5.x`) + - `@multiversx/sdk-dapp-utils` (version `2.0.0`) +- Added: + - `@multiversx/sdk-dapp-ui` (version `^0.x`) + +## 2. Changes in [`index.tsx`](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/index.tsx) + +You will need to wrap your application in a call to `initApp`: + +```tsx +initApp(config).then(() => { + ReactDOM.createRoot(document.getElementById('root')!).render( + + + + ); +}); +``` + +## 2. Summary of Changes in [`App.tsx`](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/App.tsx) + +- AxiosInterceptorContext is now created as a local component +- DappProvider was removed ❌ and initialization is now made in initApp +- NotificationModal, SignTransactionsModals and TransactionsToastList are removed ❌ and functionality is handled under the hood +- Unlock page is a child route since it only diplays a side panel over an existing route (in our case Home `/`) + +## 3. Logging in and out + +### 3.1 [Logging in](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/pages/Unlock/Unlock.tsx) + +Login buttons have been removed ❌ and there is a universal Unlock side panel, which can be inserted in the DOM at a desired location. + +> NOTE: Web-wallet URL login is no longer supported + +Example of how to use the `UnlockPanelManager` in the `unlock` route is shown below. Of course the `openUnlockPanel()` method can also be linked to a button. + +```tsx +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { UnlockPanelManager, useGetLoginInfo } from 'lib'; +import { RouteNamesEnum } from 'localConstants'; + +export const Unlock = () => { + const navigate = useNavigate(); + const { isLoggedIn } = useGetLoginInfo(); + + const unlockPanelManager = UnlockPanelManager.init({ + loginHandler: () => { + navigate(RouteNamesEnum.dashboard); + }, + onClose: () => { + navigate(RouteNamesEnum.home); + } + }); + + const handleOpenUnlockPanel = () => { + unlockPanelManager.openUnlockPanel(); + }; + + useEffect(() => { + if (isLoggedIn) { + navigate(RouteNamesEnum.dashboard); + return; + } + + handleOpenUnlockPanel(); + }, [isLoggedIn]); + + return null; +}; +``` + +- isAccountLoading has been deprecated +- `import { getIsProviderEqualTo } from “@multiversx/sdk-dapp/utils/account/getIsProviderEqualTo”` --> removed ❌ + +### 3.2 [Logging out](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/components/Layout/Header/Header.tsx#L14) + +In order to perform a logut action you simply need to get the current signing provider and call the `logout()` method: + +```typescript +import { getAccountProvider } from '@multiversx/sdk-dapp/out/providers/helpers/accountProvider'; +const provider = getAccountProvider(); +await provider.logout(); +``` + +## 4. [Sending transactions](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/helpers/signAndSendTransactions.ts) + +- `sendTransactions` and `useSendBatchTransactions` have been replaced by `provider.signTransactions`, `txManager.send` and `txManager.track` +- `newTransaction` function has been removed ❌ and you need to create `Transaction` objects directly + +## 5. [Tracking transactions](https://github.com/multiversx/mx-template-dapp/blob/423e782fec5e04b6a35b6297eaf253eb8d7ca1ba/src/helpers/signAndSendTransactions.ts#L22) + +Tracking transactions is now handled using the `txManager.track` method. You should use this method to monitor the status and outcome of your transactions after sending them. Refer to the linked file for implementation details and examples. + +```typescript + const txManager = TransactionManager.getInstance(); + + const sentTransactions = await txManager.send(signedTransactions); + const sessionId = await txManager.track(sentTransactions, { + transactionsDisplayInfo + }); +``` + + - [onFail](https://github.com/multiversx/mx-sdk-dapp/blob/0d7d9627ceccda56982a73c8ac00ed0558f0e2ec/src/hooks/transactions/useTrackTransactionStatus.ts#L34) and [onSuccess](https://github.com/multiversx/mx-sdk-dapp/blob/0d7d9627ceccda56982a73c8ac00ed0558f0e2ec/src/hooks/transactions/batch/tracker/useVerifyBatchStatus.ts#L11) callbacks can now be configured in [initApp config](https://github.com/multiversx/mx-sdk-dapp/blob/1518a070f10ef0dc133e756c07b6fc0f2165bddb/src/methods/initApp/initApp.types.ts#L42) or with [TransactionManager.setCallbacks](https://github.com/multiversx/mx-sdk-dapp/blob/1518a070f10ef0dc133e756c07b6fc0f2165bddb/src/managers/TransactionManager/TransactionManager.ts#L45) + +## 6. [UI components are now imported from sdk-dapp-core-ui](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/lib/sdkDappUI/sdkDappUI.components.ts) + + - [CopyButton.tsx](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/lib/sdkDapp/components/CopyButton/CopyButton.tsx) + - [ExplorerLink.tsx](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx) + - [FormatAmount.tsx](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx) + +Some UI components were removed: + + - [AxiosInteceptor](https://github.com/multiversx/mx-sdk-dapp/blob/old-main/src/wrappers/AxiosInterceptorContext/AxiosInterceptorContext.tsx) ❌ no longer needed because signed token can be accessed via store directly + - [IdleTimer](https://github.com/multiversx/mx-sdk-dapp/blob/old-main/src/web/hooks/useIdleTimer.tsx) ❌ must be implemented locally if needed + - [TransactionsToastList](https://github.com/multiversx/mx-sdk-dapp/blob/old-main/src/UI/TransactionsToastList/TransactionsToastList.tsx) - removed ❌ + - [SignTransactionsModals](https://github.com/multiversx/mx-sdk-dapp/blob/old-main/src/UI/SignTransactionsModals/SignTransactionsModals.tsx) - removed ❌ + - [NotificationModal](https://github.com/multiversx/mx-sdk-dapp/blob/old-main/src/UI/NotificationModal/NotificationModal.tsx) - removed ❌ + +Some new UI elements have been added: + + - [UnlockPanel](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/pages/Unlock/Unlock.tsx#L10) replaces [login buttons](https://github.com/multiversx/mx-sdk-dapp/blob/old-main/src/UI/walletConnect/WalletConnectLoginButton/WalletConnectLoginButton.tsx) + - [NotificationsFeed](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/components/Layout/Header/components/NotificationsButton.tsx) + +## 7. Methods + +- `import { deleteCustomToast } from “@multiversx/sdk-dapp/utils/toasts/customToastsActions”` --> `import { removeCustomToast } from “@multiversx/sdk-dapp/out/store/actions/toasts/toastsActions”` +- `export { setNonce } from “@multiversx/sdk-dapp/out/utils/account”;` --> `export { setAccountNonce as setNonce } from “@multiversx/sdk-dapp/out/store/actions”` +- `export { getAccount } from “@multiversx/sdk-dapp/out/utils/account”;` --> `export { getAccountFromApi as getAccount } from “@multiversx/sdk-dapp/out/apiCalls/account/getAccountFromApi”;` +- `export { + setTransactionsToSignedState, + setTransactionsDisplayInfoState, +} from “@multiversx/sdk-dapp/services/transactions/updateSignedTransactions”;` have been removed ❌ +- `export { deleteTransactionToast } from “@multiversx/sdk-dapp/services/transactions/clearTransactions”;` --> `export { removeTransactionToast as deleteTransactionToast } from “@multiversx/sdk-dapp/out/store/actions/toasts/toastsActions”;` +- `export { + addressIsValid, +} from “@multiversx/sdk-dapp/out/utils/account”;` --> `export { addressIsValid } from “@multiversx/sdk-dapp/out/utils/validation/addressIsValid”;` +- `export { getShardOfAddress } from “@multiversx/sdk-dapp/out/utils/account”;` --> +`import { AddressComputer } from “@multiversx/sdk-core/out”; +const addressComputer = new AddressComputer(); +const getShardOfAddress = addressComputer.getShardOfAddress; +export { getShardOfAddress };` +- `walletConnectDeepLink` isn now set in [initApp](https://github.com/multiversx/mx-sdk-dapp/blob/1518a070f10ef0dc133e756c07b6fc0f2165bddb/src/methods/initApp/initApp.types.ts#L23C21-L23C40) + + +## 7. [Types](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/lib/sdkDapp/sdkDapp.types.ts) + + - `LoginMethodsEnum` is replaced by `ProviderTypeEnum` + - `RawTransactionType` was removed ❌ + - some new types were added, related to UI elements, like [MvxCopyButtonPropsType](https://github.com/multiversx/mx-template-dapp/blob/a98cadfc291321e9874acd7e53632a6b43ca8c59/src/lib/sdkDapp/components/CopyButton/CopyButton.tsx#L2) diff --git a/package.json b/package.json index 1daff106..b023183d 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,11 @@ "@fortawesome/fontawesome-svg-core": "6.5.1", "@fortawesome/free-solid-svg-icons": "6.5.1", "@fortawesome/react-fontawesome": "0.2.0", - "@multiversx/sdk-core": "^14.x", - "@multiversx/sdk-dapp": "^4.x", - "axios": "1.7.4", + "@multiversx/sdk-core": "14.2.6", + "@multiversx/sdk-dapp": "^5.x", + "@multiversx/sdk-dapp-ui": "^0.x", + "@multiversx/sdk-dapp-utils": "2.0.2", + "axios": "1.10.0", "classnames": "2.3.2", "moment": "2.29.4", "react": "18.2.0", @@ -21,12 +23,12 @@ "scripts": { "lint": "eslint --ext js,ts,tsx src --fix", "run-cypress": "npx cypress run", - "start:devnet": "yarn run copy:devnet-config & vite dev", - "start:testnet": "yarn run copy:testnet-config & vite dev", - "start:mainnet": "yarn run copy:mainnet-config & vite dev", - "build:devnet": "yarn run copy:devnet-config & vite build", - "build:testnet": "yarn run copy:testnet-config & vite build", - "build:mainnet": "yarn run copy:mainnet-config & vite build", + "start:devnet": "yarn run copy:devnet-config && vite dev", + "start:testnet": "yarn run copy:testnet-config && vite dev", + "start:mainnet": "yarn run copy:mainnet-config && vite dev", + "build:devnet": "tsc & yarn run copy:devnet-config && vite build", + "build:testnet": "tsc & yarn run copy:testnet-config && vite build", + "build:mainnet": "tsc & yarn run copy:mainnet-config && vite build", "copy:devnet-config": "cp ./src/config/config.devnet.ts ./src/config/index.ts", "copy:testnet-config": "cp ./src/config/config.testnet.ts ./src/config/index.ts", "copy:mainnet-config": "cp ./src/config/config.mainnet.ts ./src/config/index.ts", @@ -49,13 +51,12 @@ "@types/jest": "29.5.5", "@types/node": "20.7.1", "@types/react": "18.2.23", - "@types/react-dom": "18.2.8", "@types/react-router-dom": "5.3.3", "@typescript-eslint/eslint-plugin": "6.7.0", "@typescript-eslint/parser": "6.7.0", - "@vitejs/plugin-basic-ssl": "^1.0.1", + "@vitejs/plugin-basic-ssl": "1.0.1", "@vitejs/plugin-react": "4.1.0", - "@wdio/cli": "^8.33.1", + "@wdio/cli": "8.33.1", "@wdio/concise-reporter": "8.32.4", "@wdio/local-runner": "8.32.4", "@wdio/mocha-framework": "8.32.4", @@ -68,7 +69,7 @@ "eslint-plugin-prettier": "5.0.0", "eslint-plugin-react": "7.33.2", "eslint-plugin-react-hooks": "4.6.0", - "eslint-plugin-sort-exports": "^0.9.1", + "eslint-plugin-sort-exports": "0.9.1", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-watch-typeahead": "2.2.2", diff --git a/src/App.tsx b/src/App.tsx index b4240d1f..7638e3b6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,86 +1,36 @@ import { Route, BrowserRouter as Router, Routes } from 'react-router-dom'; -import { Layout } from 'components'; -import { - apiTimeout, - environment, - sampleAuthenticatedDomains, - walletConnectV2ProjectId -} from 'config'; -import { - AxiosInterceptorContext, // using this is optional - DappProvider, - NotificationModal, - SignTransactionsModals, - TransactionsToastList - // uncomment this to use the custom transaction tracker - // TransactionsTracker -} from 'lib'; -import { RouteNamesEnum } from 'localConstants'; -import { PageNotFound } from 'pages'; +import { PageNotFound } from 'pages/PageNotFound/PageNotFound'; import { routes } from 'routes'; -import { BatchTransactionsContextProvider } from 'wrappers'; - -const AppContent = () => { - return ( - { - console.log(`Session ${sessionId} successfully completed`); - }, - onFail: (sessionId: string, errorMessage: string) => { - console.log(`Session ${sessionId} failed. ${errorMessage ?? ''}`); - } - } - } - }} - > - - - - - - - {routes.map((route) => ( - } - /> - ))} - } /> - - - - - ); -}; +import { AxiosInterceptors, BatchTransactionsContextProvider } from 'wrappers'; +import { Layout } from './components'; export const App = () => { return ( - - - - - - - - - + + + + + + {routes.map((route) => ( + } + > + {route.children?.map((child) => ( + } + /> + ))} + + ))} + } /> + + + + + ); }; diff --git a/src/components/ContractAddress/ContractAddress.tsx b/src/components/ContractAddress/ContractAddress.tsx index c53d849f..47336193 100644 --- a/src/components/ContractAddress/ContractAddress.tsx +++ b/src/components/ContractAddress/ContractAddress.tsx @@ -1,17 +1,28 @@ import { Label } from 'components'; import { contractAddress } from 'config'; -import { ACCOUNTS_ENDPOINT, ExplorerLink } from 'lib'; +import { + ACCOUNTS_ENDPOINT, + getExplorerLink, + MvxExplorerLink, + useGetNetworkConfig +} from 'lib'; export const ContractAddress = () => { + const { network } = useGetNetworkConfig(); + const explorerAddress = network.explorerAddress; + const explorerLink = getExplorerLink({ + to: `/${ACCOUNTS_ENDPOINT}/${contractAddress}`, + explorerAddress + }); return (

- {contractAddress} - +

); }; diff --git a/src/components/Layout/Header/Header.tsx b/src/components/Layout/Header/Header.tsx index 829f30e4..29eaabc7 100644 --- a/src/components/Layout/Header/Header.tsx +++ b/src/components/Layout/Header/Header.tsx @@ -1,47 +1,19 @@ -import { useMatch } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { Button, MxLink } from 'components'; import { environment } from 'config'; -import { logout, useGetIsLoggedIn } from 'lib'; +import { getAccountProvider, useGetIsLoggedIn } from 'lib'; import { RouteNamesEnum } from 'localConstants'; import MultiversXLogo from '../../../assets/img/multiversx-logo.svg?react'; - -const callbackUrl = `${window.location.origin}/unlock`; -const onRedirect = undefined; // use this to redirect with useNavigate to a specific page after logout -const shouldAttemptReLogin = false; // use for special cases where you want to re-login after logout -const options = { - /* - * @param {boolean} [shouldBroadcastLogoutAcrossTabs=true] - * @description If your dApp supports multiple accounts on multiple tabs, - * this param will broadcast the logout event across all tabs. - */ - shouldBroadcastLogoutAcrossTabs: true, - /* - * @param {boolean} [hasConsentPopup=false] - * @description Set it to true if you want to perform async calls before logging out on Safari. - * It will open a consent popup for the user to confirm the action before leaving the page. - */ - hasConsentPopup: false -}; +import { NotificationsButton } from './components/NotificationsButton'; export const Header = () => { const isLoggedIn = useGetIsLoggedIn(); - const isUnlockRoute = Boolean(useMatch(RouteNamesEnum.unlock)); - - const ConnectButton = isUnlockRoute ? null : ( - Connect - ); + const navigate = useNavigate(); + const provider = getAccountProvider(); - const handleLogout = () => { - sessionStorage.clear(); - logout( - callbackUrl, - /* - * following are optional params. Feel free to remove them in your implementation - */ - onRedirect, - shouldAttemptReLogin, - options - ); + const handleLogout = async () => { + await provider.logout(); + navigate(RouteNamesEnum.home); }; return ( @@ -60,15 +32,26 @@ export const Header = () => {

{environment}

- {isLoggedIn ? ( + {isLoggedIn && ( + <> + + + + )} + + {!isLoggedIn && ( - ) : ( - ConnectButton )} diff --git a/src/components/Layout/Header/components/NotificationsButton.tsx b/src/components/Layout/Header/components/NotificationsButton.tsx new file mode 100644 index 00000000..6f4a26b6 --- /dev/null +++ b/src/components/Layout/Header/components/NotificationsButton.tsx @@ -0,0 +1,19 @@ +import { faBell } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button } from 'components'; +import { NotificationsFeedManager } from 'lib'; + +export const NotificationsButton = () => { + const handleOpenNotificationsFeed = async () => { + await NotificationsFeedManager.getInstance().openNotificationsFeed(); + }; + + return ( + + ); +}; diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx new file mode 100644 index 00000000..c40a4641 --- /dev/null +++ b/src/components/Loader/Loader.tsx @@ -0,0 +1,14 @@ +import { faSpinner } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +export const Loader = () => { + return ( +
+ +
+ ); +}; diff --git a/src/components/Loader/index.tsx b/src/components/Loader/index.tsx new file mode 100644 index 00000000..d5ce9811 --- /dev/null +++ b/src/components/Loader/index.tsx @@ -0,0 +1 @@ +export * from './Loader'; diff --git a/src/components/OutputContainer/OutputContainer.tsx b/src/components/OutputContainer/OutputContainer.tsx index 1f9c03cc..6381b1c3 100644 --- a/src/components/OutputContainer/OutputContainer.tsx +++ b/src/components/OutputContainer/OutputContainer.tsx @@ -1,6 +1,7 @@ import classNames from 'classnames'; import { PropsWithChildren } from 'react'; -import { Loader, WithClassnameType } from 'lib'; +import { Loader } from 'components'; +import { WithClassnameType } from 'types'; interface OutputContainerPropsType extends PropsWithChildren, diff --git a/src/components/OutputContainer/components/PingPongOutput.tsx b/src/components/OutputContainer/components/PingPongOutput.tsx index 34af887c..a2c5ce9d 100644 --- a/src/components/OutputContainer/components/PingPongOutput.tsx +++ b/src/components/OutputContainer/components/PingPongOutput.tsx @@ -13,7 +13,7 @@ export const PingPongOutput = ({ pongAllowed, transactions }: PingPongOutputType) => { - if (!transactions) { + if (!transactions || transactions?.length === 0) { return null; } diff --git a/src/components/OutputContainer/components/TransactionOutput.tsx b/src/components/OutputContainer/components/TransactionOutput.tsx index 9a42f78b..38014328 100644 --- a/src/components/OutputContainer/components/TransactionOutput.tsx +++ b/src/components/OutputContainer/components/TransactionOutput.tsx @@ -1,13 +1,17 @@ import { Label } from 'components'; import { ACCOUNTS_ENDPOINT, - ExplorerLink, - FormatAmount, + DECIMALS, + DIGITS, + FormatAmountController, + getExplorerLink, + MvxExplorerLink, + MvxFormatAmount, SignedTransactionType, TRANSACTIONS_ENDPOINT, + useGetAccountInfo, useGetNetworkConfig } from 'lib'; -import { DataTestIdsEnum } from 'localConstants'; export const TransactionOutput = ({ transaction @@ -15,37 +19,58 @@ export const TransactionOutput = ({ transaction: SignedTransactionType; }) => { const { network } = useGetNetworkConfig(); + const { account } = useGetAccountInfo(); const decodedData = transaction.data ? Buffer.from(transaction.data, 'base64').toString('ascii') : 'N/A'; + + const { isValid, valueDecimal, valueInteger, label } = + FormatAmountController.getData({ + digits: DIGITS, + decimals: DECIMALS, + egldLabel: network.egldLabel, + input: account.balance + }); + + const explorerAddress = network.explorerAddress; + const hashExplorerLink = getExplorerLink({ + to: `/${TRANSACTIONS_ENDPOINT}/${transaction.hash}`, + explorerAddress + }); + const receiverExplorerLink = getExplorerLink({ + to: `/${ACCOUNTS_ENDPOINT}/${transaction.receiver}`, + explorerAddress + }); + return (

- {transaction.hash} - +

- {transaction.receiver} - +

-

diff --git a/src/components/OutputContainer/components/TransactionsOutput.tsx b/src/components/OutputContainer/components/TransactionsOutput.tsx index a21c6e81..03f576f3 100644 --- a/src/components/OutputContainer/components/TransactionsOutput.tsx +++ b/src/components/OutputContainer/components/TransactionsOutput.tsx @@ -10,10 +10,7 @@ export const TransactionsOutput = ({

{transactions?.map((transaction) => { return ( - + ); })}
diff --git a/src/components/TransactionsTable/TransactionsTable.tsx b/src/components/TransactionsTable/TransactionsTable.tsx new file mode 100644 index 00000000..de1c5d50 --- /dev/null +++ b/src/components/TransactionsTable/TransactionsTable.tsx @@ -0,0 +1,41 @@ +import { useEffect, useState } from 'react'; +import { + MvxTransactionsTable, + ServerTransactionType, + TransactionsRowType, + TransactionsTableController, + useGetAccount, + useGetNetworkConfig +} from 'lib'; + +interface TransactionsTablePropsType { + transactions?: ServerTransactionType[]; +} + +export const TransactionsTable = ({ + transactions = [] +}: TransactionsTablePropsType) => { + const { address } = useGetAccount(); + const { network } = useGetNetworkConfig(); + const [processedTransaction, setProcessedTransactions] = useState< + TransactionsRowType[] + >([]); + + useEffect(() => { + processTransactions(); + }, []); + + const processTransactions = async () => { + const transactionsData = + await TransactionsTableController.processTransactions({ + address, + egldLabel: network.egldLabel, + explorerAddress: network.explorerAddress, + transactions + }); + + setProcessedTransactions(transactionsData); + }; + + return ; +}; diff --git a/src/components/TransactionsTable/index.ts b/src/components/TransactionsTable/index.ts new file mode 100644 index 00000000..41036d18 --- /dev/null +++ b/src/components/TransactionsTable/index.ts @@ -0,0 +1 @@ +export * from './TransactionsTable'; diff --git a/src/components/TransactionsTracker/TransactionsTracker.ts b/src/components/TransactionsTracker/TransactionsTracker.ts deleted file mode 100644 index 081e94de..00000000 --- a/src/components/TransactionsTracker/TransactionsTracker.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { useBatchTransactionsTracker, useTransactionsTracker } from 'lib'; - -export const TransactionsTracker = () => { - useTransactionsTracker({ - onSuccess: (sessionId: string) => { - console.log(`Session ${sessionId} successfully completed`); - }, - onFail: (sessionId: string, errorMessage?: string) => { - if (errorMessage) { - console.log(`Session ${sessionId} failed, ${errorMessage}`); - return; - } - - console.log(`Session ${sessionId} failed`); - } - }); - // We do this in order to have full control of the implementation - // Default tracker sends signedTransactions automatically and we don't want to do that - // By doing this it will enable the tracker but without the sendTransactions logic - useBatchTransactionsTracker({ - onSuccess: (sessionId) => { - console.log(`Batch with session ${sessionId} successfully completed`); - }, - onFail: (sessionId, errorMessage) => { - if (errorMessage) { - console.log(`Batch with session ${sessionId} failed, ${errorMessage}`); - return; - } - - console.log(`Batch with session ${sessionId} failed`); - } - }); - - return null; -}; diff --git a/src/components/TransactionsTracker/index.ts b/src/components/TransactionsTracker/index.ts deleted file mode 100644 index 4e1911f7..00000000 --- a/src/components/TransactionsTracker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './TransactionsTracker'; diff --git a/src/components/index.ts b/src/components/index.ts index ad6b41fd..de768795 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -3,7 +3,8 @@ export * from './Card'; export * from './ContractAddress'; export * from './Label'; export * from './Layout'; +export * from './Loader'; export * from './MissingNativeAuthError'; export * from './MxLink'; export * from './OutputContainer'; -export * from './TransactionsTracker'; +export * from './TransactionsTable'; diff --git a/src/helpers/signAndSendTransactions.ts b/src/helpers/signAndSendTransactions.ts index 4dc48f14..d272d77a 100644 --- a/src/helpers/signAndSendTransactions.ts +++ b/src/helpers/signAndSendTransactions.ts @@ -1,29 +1,26 @@ -import { refreshAccount, sendTransactions } from 'lib'; -import { isSafari } from 'localConstants'; -import { Transaction, TransactionsDisplayInfoType } from 'types'; +import { + getAccountProvider, + Transaction, + TransactionManager, + TransactionsDisplayInfoType +} from 'lib'; type SignAndSendTransactionsProps = { transactions: Transaction[]; - callbackRoute: string; - transactionsDisplayInfo: TransactionsDisplayInfoType; + transactionsDisplayInfo?: TransactionsDisplayInfoType; }; export const signAndSendTransactions = async ({ transactions, - callbackRoute, transactionsDisplayInfo }: SignAndSendTransactionsProps) => { - await refreshAccount(); + const provider = getAccountProvider(); + const txManager = TransactionManager.getInstance(); - const { sessionId } = await sendTransactions({ - transactions, - transactionsDisplayInfo, - redirectAfterSign: false, - callbackRoute, - // NOTE: performing async calls (eg: `await refreshAccount()`) before opening a new tab - // can cause the new tab to be blocked by Safari's popup blocker. - // To support this feature, we can set `hasConsentPopup` to `true` - hasConsentPopup: isSafari + const signedTransactions = await provider.signTransactions(transactions); + const sentTransactions = await txManager.send(signedTransactions); + const sessionId = await txManager.track(sentTransactions, { + transactionsDisplayInfo }); return sessionId; diff --git a/src/hooks/index.ts b/src/hooks/index.ts index d57e8f41..4ba6c2eb 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,4 +1,2 @@ export * from './transactions'; -export * from './useIsWebProvider'; -export * from './useScrollToElement'; export * from './useWindowSize'; diff --git a/src/hooks/transactions/useSendPingPongTransaction.ts b/src/hooks/transactions/useSendPingPongTransaction.ts index dcb87fb8..50905c69 100644 --- a/src/hooks/transactions/useSendPingPongTransaction.ts +++ b/src/hooks/transactions/useSendPingPongTransaction.ts @@ -1,34 +1,16 @@ -import { - AbiRegistry, - SmartContractTransactionsFactory, - TransactionsFactoryConfig -} from '@multiversx/sdk-core/out'; -import { useCallback, useState } from 'react'; +import axios from 'axios'; import { contractAddress } from 'config'; -import pingPongAbi from 'contracts/ping-pong.abi.json'; -import { signAndSendTransactions } from 'helpers/signAndSendTransactions'; +import { signAndSendTransactions } from 'helpers'; import { + AbiRegistry, Address, - deleteTransactionToast, GAS_PRICE, - newTransaction, - removeAllSignedTransactions, - removeAllTransactionsToSign, - useGetAccountInfo, - useGetNetworkConfig, - useTrackTransactionStatus, - VERSION + SmartContractTransactionsFactory, + Transaction, + TransactionsFactoryConfig, + useGetAccount, + useGetNetworkConfig } from 'lib'; -import { SessionEnum } from 'localConstants'; -import { - PingPongServiceProps, - PingRawProps, - PongRawProps -} from 'types/pingPong.types'; - -type PingPongTransactionProps = { - type: SessionEnum; -}; const PING_TRANSACTION_INFO = { processingMessage: 'Processing Ping transaction', @@ -42,59 +24,13 @@ const PONG_TRANSACTION_INFO = { successMessage: 'Pong transaction successful' }; -export const useSendPingPongTransaction = ({ - type -}: PingPongTransactionProps) => { - // Needed in order to differentiate widgets between each other - // By default sdk-dapp takes the last sessionId available which will display on every widget the same transaction - // this usually appears on page refreshes - const [pingPongSessionId, setPingPongSessionId] = useState( - sessionStorage.getItem(type) - ); - +export const useSendPingPongTransaction = () => { const { network } = useGetNetworkConfig(); - const { address, account } = useGetAccountInfo(); - - const transactionStatus = useTrackTransactionStatus({ - transactionId: pingPongSessionId ?? '0' - }); - - const clearAllTransactions = () => { - removeAllSignedTransactions(); - removeAllTransactionsToSign(); - deleteTransactionToast(pingPongSessionId ?? ''); - }; - - const sendPingTransaction = useCallback( - async ({ amount, callbackRoute }: PingRawProps) => { - clearAllTransactions(); - - const pingTransaction = newTransaction({ - value: amount, - data: 'ping', - receiver: contractAddress, - gasLimit: 60000000, - gasPrice: GAS_PRICE, - chainID: network.chainId, - nonce: account.nonce, - sender: address, - version: VERSION - }); - - const sessionId = await signAndSendTransactions({ - transactions: [pingTransaction], - callbackRoute, - transactionsDisplayInfo: PING_TRANSACTION_INFO - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }, - [] - ); + const { address } = useGetAccount(); const getSmartContractFactory = async () => { - const abi = AbiRegistry.create(pingPongAbi); + const response = await axios.get('src/contracts/ping-pong.abi.json'); + const abi = AbiRegistry.create(response.data); const scFactory = new SmartContractTransactionsFactory({ config: new TransactionsFactoryConfig({ chainID: network.chainId @@ -105,119 +41,101 @@ export const useSendPingPongTransaction = ({ return scFactory; }; - const sendPingTransactionFromAbi = useCallback( - async ({ amount, callbackRoute }: PingRawProps) => { - clearAllTransactions(); - - const scFactory = await getSmartContractFactory(); - const pingTransaction = scFactory.createTransactionForExecute( - new Address(address), - { - gasLimit: BigInt(60000000), - function: 'ping', - contract: new Address(contractAddress), - nativeTransferAmount: BigInt(amount) - } - ); - - const sessionId = await signAndSendTransactions({ - transactions: [pingTransaction], - callbackRoute, - transactionsDisplayInfo: PING_TRANSACTION_INFO - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }, - [] - ); - - const sendPingTransactionFromService = useCallback( - async ({ transactions, callbackRoute }: PingPongServiceProps) => { - clearAllTransactions(); - - const sessionId = await signAndSendTransactions({ - transactions, - callbackRoute, - transactionsDisplayInfo: PING_TRANSACTION_INFO - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }, - [] - ); - - const sendPongTransaction = useCallback( - async ({ callbackRoute }: PongRawProps) => { - clearAllTransactions(); - - const pongTransaction = newTransaction({ - value: '0', - data: 'pong', - receiver: contractAddress, - gasLimit: 60000000, - gasPrice: GAS_PRICE, - chainID: network.chainId, - nonce: account.nonce, - sender: address, - version: VERSION - }); - - const sessionId = await signAndSendTransactions({ - transactions: [pongTransaction], - callbackRoute, - transactionsDisplayInfo: PONG_TRANSACTION_INFO - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }, - [] - ); - - const sendPongTransactionFromAbi = useCallback( - async ({ callbackRoute }: PongRawProps) => { - clearAllTransactions(); - - const scFactory = await getSmartContractFactory(); - const pongTransaction = scFactory.createTransactionForExecute( - new Address(address), - { - gasLimit: BigInt(60000000), - function: 'pong', - contract: new Address(contractAddress), - nativeTransferAmount: BigInt(0) - } - ); - - const sessionId = await signAndSendTransactions({ - transactions: [pongTransaction], - callbackRoute, - transactionsDisplayInfo: PONG_TRANSACTION_INFO - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }, - [] - ); - - const sendPongTransactionFromService = useCallback( - async ({ transactions, callbackRoute }: PingPongServiceProps) => { - clearAllTransactions(); - - const sessionId = await signAndSendTransactions({ - transactions, - callbackRoute, - transactionsDisplayInfo: PONG_TRANSACTION_INFO - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }, - [] - ); + const sendPingTransaction = async (amount: string) => { + const pingTransaction = new Transaction({ + value: BigInt(amount), + data: Buffer.from('ping'), + receiver: new Address(contractAddress), + gasLimit: BigInt(6000000), + gasPrice: BigInt(GAS_PRICE), + chainID: network.chainId, + sender: new Address(address), + version: 1 + }); + + await signAndSendTransactions({ + transactions: [pingTransaction], + transactionsDisplayInfo: PING_TRANSACTION_INFO + }); + }; + + const sendPingTransactionFromAbi = async (amount: string) => { + const scFactory = await getSmartContractFactory(); + const pingTransaction = scFactory.createTransactionForExecute( + new Address(address), + { + gasLimit: BigInt(6000000), + function: 'ping', + contract: new Address(contractAddress), + nativeTransferAmount: BigInt(amount) + } + ); + + const sessionId = await signAndSendTransactions({ + transactions: [pingTransaction], + transactionsDisplayInfo: PING_TRANSACTION_INFO + }); + + return sessionId; + }; + + const sendPingTransactionFromService = async ( + transactions: Transaction[] + ) => { + await signAndSendTransactions({ + transactions, + transactionsDisplayInfo: PING_TRANSACTION_INFO + }); + }; + + const sendPongTransaction = async () => { + const pongTransaction = new Transaction({ + value: BigInt(0), + data: Buffer.from('pong'), + receiver: new Address(contractAddress), + gasLimit: BigInt(6000000), + gasPrice: BigInt(GAS_PRICE), + chainID: network.chainId, + sender: new Address(address), + version: 1 + }); + + await signAndSendTransactions({ + transactions: [pongTransaction], + transactionsDisplayInfo: PONG_TRANSACTION_INFO + }); + }; + + const sendPongTransactionFromAbi = async () => { + const scFactory = await getSmartContractFactory(); + const pongTransaction = scFactory.createTransactionForExecute( + new Address(address), + { + gasLimit: BigInt(6000000), + function: 'pong', + contract: new Address(contractAddress), + nativeTransferAmount: BigInt(0) + } + ); + + const sessionId = await signAndSendTransactions({ + transactions: [pongTransaction], + transactionsDisplayInfo: PONG_TRANSACTION_INFO + }); + + return sessionId; + }; + + const sendPongTransactionFromService = async ( + transactions: Transaction[] + ) => { + const sessionId = await signAndSendTransactions({ + transactions, + transactionsDisplayInfo: PONG_TRANSACTION_INFO + }); + + return sessionId; + }; return { sendPingTransaction, @@ -225,7 +143,6 @@ export const useSendPingPongTransaction = ({ sendPongTransaction, sendPongTransactionFromAbi, sendPingTransactionFromService, - sendPongTransactionFromService, - transactionStatus + sendPongTransactionFromService }; }; diff --git a/src/hooks/useIsWebProvider.ts b/src/hooks/useIsWebProvider.ts deleted file mode 100644 index 3b41ea78..00000000 --- a/src/hooks/useIsWebProvider.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { LoginMethodsEnum, useGetAccountProvider } from 'lib'; - -export const useIsWebProvider = () => { - const { providerType } = useGetAccountProvider(); - const isWebProvider = providerType === LoginMethodsEnum.wallet; - - return { isWebProvider }; -}; diff --git a/src/hooks/useScrollToElement.ts b/src/hooks/useScrollToElement.ts deleted file mode 100644 index 62489666..00000000 --- a/src/hooks/useScrollToElement.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; - -export const useScrollToElement = () => { - const location = useLocation(); - - useEffect(() => { - const [, anchor] = location.hash.split('#'); - - if (!anchor) { - return; - } - - const element = document.getElementById(anchor); - - if (!element) { - return; - } - - element.scrollIntoView(); - }, [location.hash]); -}; diff --git a/src/index.tsx b/src/index.tsx index 44bfaf02..da6a66f7 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,7 +1,13 @@ -import { createRoot } from 'react-dom/client'; -import './styles/globals.css'; +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { initApp } from 'lib'; import { App } from './App'; +import { config } from './initConfig'; -const container = document.getElementById('root'); -const root = createRoot(container as HTMLElement); -root.render(() as any); +initApp(config).then(() => { + ReactDOM.createRoot(document.getElementById('root')!).render( + + + + ); +}); diff --git a/src/initConfig.ts b/src/initConfig.ts new file mode 100644 index 00000000..7b13c53f --- /dev/null +++ b/src/initConfig.ts @@ -0,0 +1,34 @@ +import './styles/globals.css'; + +import { walletConnectV2ProjectId } from 'config'; +import { EnvironmentsEnum, ICustomProvider, InitAppType } from './lib'; +import { InMemoryProvider } from './provider/inMemoryProvider'; + +const providers: ICustomProvider[] = [ + { + name: 'In Memory Provider', + type: 'inMemoryProvider', + iconUrl: `${window.location.origin}/multiversx-white.svg`, + constructor: async (options) => new InMemoryProvider(options) + } +]; + +(window as any).multiversx = {}; +// Option 1: Add providers using the `window.providers` array +(window as any).multiversx.providers = providers; + +export const config: InitAppType = { + storage: { getStorageCallback: () => sessionStorage }, + dAppConfig: { + nativeAuth: true, + environment: EnvironmentsEnum.devnet, + providers: { + walletConnect: { + walletConnectV2ProjectId + } + } + } + + // Option 2: Add providers using the config `customProviders` array + // customProviders: [providers] +}; diff --git a/src/lib/index.ts b/src/lib/index.ts index 6a1ace50..e430b05e 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,2 +1,4 @@ export * from './sdkCore'; export * from './sdkDapp'; +export * from './sdkDappUI'; +export * from './sdkDappUtils'; diff --git a/src/lib/sdkCore.ts b/src/lib/sdkCore.ts index 88751e24..a7b28c49 100644 --- a/src/lib/sdkCore.ts +++ b/src/lib/sdkCore.ts @@ -4,9 +4,17 @@ export { AddressValue, ContractFunction, Message, + MessageComputer, ProxyNetworkProvider, SmartContract, SmartContractController, + SmartContractTransactionsFactory, + Token, TokenTransfer, - Transaction + Transaction, + TransactionComputer, + TransactionsFactoryConfig, + TransferTransactionsFactory, + UserSecretKey, + UserSigner } from '@multiversx/sdk-core'; diff --git a/src/lib/sdkDapp/components/CopyButton/CopyButton.tsx b/src/lib/sdkDapp/components/CopyButton/CopyButton.tsx new file mode 100644 index 00000000..19f1dc21 --- /dev/null +++ b/src/lib/sdkDapp/components/CopyButton/CopyButton.tsx @@ -0,0 +1,20 @@ +import { MvxCopyButton } from 'lib/sdkDappUI/sdkDappUI.components'; +import { MvxCopyButtonPropsType } from 'lib/sdkDappUI/sdkDappUI.types'; + +export const CopyButton = ({ + className, + text, + copyIcon, + iconClass, + successIcon +}: Partial) => { + return ( + + ); +}; diff --git a/src/lib/sdkDapp/components/CopyButton/index.ts b/src/lib/sdkDapp/components/CopyButton/index.ts new file mode 100644 index 00000000..367e65cb --- /dev/null +++ b/src/lib/sdkDapp/components/CopyButton/index.ts @@ -0,0 +1 @@ +export * from './CopyButton'; diff --git a/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx b/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx new file mode 100644 index 00000000..cb725baf --- /dev/null +++ b/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx @@ -0,0 +1,29 @@ +import { PropsWithChildren } from 'react'; +import { useGetNetworkConfig } from 'lib/sdkDapp/sdkDapp.hooks'; +import { MvxExplorerLink } from 'lib/sdkDappUI/sdkDappUI.components'; +import { WithClassnameType } from 'types/components.types'; + +export const ExplorerLink = ({ + children, + page, + className, + 'data-testid': dataTestId +}: ExplorerLinkPropsType) => { + const { network } = useGetNetworkConfig(); + + return ( + + {children ? {children} : null} + + ); +}; + +export interface ExplorerLinkPropsType + extends WithClassnameType, + PropsWithChildren { + page: string; +} diff --git a/src/lib/sdkDapp/components/ExplorerLink/index.ts b/src/lib/sdkDapp/components/ExplorerLink/index.ts new file mode 100644 index 00000000..0c7d53d6 --- /dev/null +++ b/src/lib/sdkDapp/components/ExplorerLink/index.ts @@ -0,0 +1 @@ +export * from './ExplorerLink'; diff --git a/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx b/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx new file mode 100644 index 00000000..6ea159a4 --- /dev/null +++ b/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx @@ -0,0 +1,39 @@ +import { WithClassnameType } from 'types'; +import { MvxFormatAmount } from '../../../sdkDappUI/sdkDappUI.components'; +import { MvxFormatAmountPropsType } from '../../../sdkDappUI/sdkDappUI.types'; +import { DECIMALS, DIGITS } from '../../../sdkDappUtils'; +import { FormatAmountController } from '../../sdkDapp.helpers'; +import { useGetNetworkConfig } from '../../sdkDapp.hooks'; + +interface IFormatAmountProps + extends Partial, + WithClassnameType { + value: string; +} + +export const FormatAmount = (props: IFormatAmountProps) => { + const { + network: { egldLabel } + } = useGetNetworkConfig(); + + const { isValid, valueDecimal, valueInteger, label } = + FormatAmountController.getData({ + digits: DIGITS, + decimals: DECIMALS, + egldLabel, + ...props, + input: props.value + }); + + return ( + + ); +}; diff --git a/src/lib/sdkDapp/components/FormatAmount/index.ts b/src/lib/sdkDapp/components/FormatAmount/index.ts new file mode 100644 index 00000000..3578b893 --- /dev/null +++ b/src/lib/sdkDapp/components/FormatAmount/index.ts @@ -0,0 +1 @@ +export * from './FormatAmount'; diff --git a/src/lib/sdkDapp/components/index.tsx b/src/lib/sdkDapp/components/index.tsx new file mode 100644 index 00000000..b4193d3b --- /dev/null +++ b/src/lib/sdkDapp/components/index.tsx @@ -0,0 +1,3 @@ +export * from './CopyButton'; +export * from './ExplorerLink'; +export * from './FormatAmount'; diff --git a/src/lib/sdkDapp/index.ts b/src/lib/sdkDapp/index.ts index 4f89aa43..b347b18f 100644 --- a/src/lib/sdkDapp/index.ts +++ b/src/lib/sdkDapp/index.ts @@ -1,4 +1,4 @@ -export * from './sdkDapp.components'; +export * from './components'; export * from './sdkDapp.constants'; export * from './sdkDapp.helpers'; export * from './sdkDapp.hooks'; diff --git a/src/lib/sdkDapp/sdkDapp.components.ts b/src/lib/sdkDapp/sdkDapp.components.ts deleted file mode 100644 index eec2024e..00000000 --- a/src/lib/sdkDapp/sdkDapp.components.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * components get re-exported because it makes the build size smaller - * and allows testing with Jest (see `moduleNameMapper` in package.json) - */ -export { ACCOUNTS_ENDPOINT } from '@multiversx/sdk-dapp/apiCalls/endpoints'; -export { AxiosInterceptorContext } from '@multiversx/sdk-dapp/wrappers/AxiosInterceptorContext/AxiosInterceptorContext'; -export { CopyButton } from '@multiversx/sdk-dapp/UI/CopyButton/CopyButton'; -export { CrossWindowLoginButton } from '@multiversx/sdk-dapp/UI/webWallet/CrossWindowLoginButton/CrossWindowLoginButton'; -export { DappProvider } from '@multiversx/sdk-dapp/wrappers/DappProvider/DappProvider'; -export { ExplorerLink } from '@multiversx/sdk-dapp/UI/ExplorerLink'; -export { ExtensionLoginButton } from '@multiversx/sdk-dapp/UI/extension/ExtensionLoginButton/ExtensionLoginButton'; -export { FormatAmount } from '@multiversx/sdk-dapp/UI/FormatAmount/FormatAmount'; -export { IframeButton } from '@multiversx/sdk-dapp/UI/iframe/IframeLoginButton/IframeButton'; -export { LedgerLoginButton } from '@multiversx/sdk-dapp/UI/ledger/LedgerLoginButton/LedgerLoginButton'; -export { Loader } from '@multiversx/sdk-dapp/UI/Loader/Loader'; -export { NotificationModal } from '@multiversx/sdk-dapp/UI/NotificationModal/NotificationModal'; -export { OperaWalletLoginButton } from '@multiversx/sdk-dapp/UI/operaWallet/OperaWalletLoginButton/OperaWalletLoginButton'; -export { PageState } from '@multiversx/sdk-dapp/UI/PageState/PageState'; -export { SignTransactionsModals } from '@multiversx/sdk-dapp/UI/SignTransactionsModals/SignTransactionsModals'; -export { TransactionRow } from '@multiversx/sdk-dapp/UI/TransactionsTable/components/TransactionRow'; -export { TransactionsTable } from '@multiversx/sdk-dapp/UI/TransactionsTable/TransactionsTable'; -export { TransactionsToastList } from '@multiversx/sdk-dapp/UI/TransactionsToastList/TransactionsToastList'; -export { WalletConnectLoginButton } from '@multiversx/sdk-dapp/UI/walletConnect/WalletConnectLoginButton/WalletConnectLoginButton'; -export { WebWalletLoginButton } from '@multiversx/sdk-dapp/UI/webWallet/WebWalletLoginButton/WebWalletLoginButton'; -export { XaliasCrossWindowLoginButton } from '@multiversx/sdk-dapp/UI/webWallet/XaliasCrossWindowLoginButton/XaliasCrossWindowLoginButton'; -export { XaliasLoginButton } from '@multiversx/sdk-dapp/UI/webWallet/XaliasLoginButton/XaliasLoginButton'; diff --git a/src/lib/sdkDapp/sdkDapp.constants.ts b/src/lib/sdkDapp/sdkDapp.constants.ts index e5e48aec..04d62a38 100644 --- a/src/lib/sdkDapp/sdkDapp.constants.ts +++ b/src/lib/sdkDapp/sdkDapp.constants.ts @@ -1,9 +1,8 @@ export { - DECIMALS, - EXTRA_GAS_LIMIT_GUARDED_TX, - GAS_LIMIT, + ACCOUNTS_ENDPOINT, + TRANSACTIONS_ENDPOINT +} from '@multiversx/sdk-dapp/out/apiCalls/endpoints'; +export { GAS_PRICE, - VERSION, - WALLET_PROVIDER_SEND_TRANSACTION_URL -} from '@multiversx/sdk-dapp/constants'; -export { TRANSACTIONS_ENDPOINT } from '@multiversx/sdk-dapp/apiCalls/endpoints'; + VERSION +} from '@multiversx/sdk-dapp/out/constants/mvx.constants'; diff --git a/src/lib/sdkDapp/sdkDapp.helpers.ts b/src/lib/sdkDapp/sdkDapp.helpers.ts index 45edd1fc..174f60cd 100644 --- a/src/lib/sdkDapp/sdkDapp.helpers.ts +++ b/src/lib/sdkDapp/sdkDapp.helpers.ts @@ -1,22 +1,15 @@ -export { addressIsValid } from '@multiversx/sdk-dapp/utils/account/addressIsValid'; -export { - deleteTransactionToast, - removeAllSignedTransactions, - removeAllTransactionsToSign -} from '@multiversx/sdk-dapp/services/transactions/clearTransactions'; -export { getInterpretedTransaction } from '@multiversx/sdk-dapp/utils/transactions/getInterpretedTransaction'; -export { getIsProviderEqualTo } from '@multiversx/sdk-dapp/utils/account/getIsProviderEqualTo'; -export { getTransactions } from '@multiversx/sdk-dapp/apiCalls/transactions/getTransactions'; -export { logout } from '@multiversx/sdk-dapp/utils/logout'; -export { newTransaction } from '@multiversx/sdk-dapp/models'; -export { parseAmount } from '@multiversx/sdk-dapp/utils/operations/parseAmount'; -export { refreshAccount } from '@multiversx/sdk-dapp/utils/account/refreshAccount'; -export { sendBatchTransactions } from '@multiversx/sdk-dapp/services/transactions/sendBatchTransactions'; -export { sendTransactions } from '@multiversx/sdk-dapp/services/transactions/sendTransactions'; -export { - setTransactionsDisplayInfoState, - setTransactionsToSignedState -} from '@multiversx/sdk-dapp/services/transactions/updateSignedTransactions'; -export { signTransactions } from '@multiversx/sdk-dapp/services/transactions/signTransactions'; -export { trimUsernameDomain } from '@multiversx/sdk-dapp/hooks/account/helpers'; -export { verifyMessage } from '@multiversx/sdk-dapp/hooks/signMessage/verifyMessage'; +export { FormatAmountController } from '@multiversx/sdk-dapp/out/controllers/FormatAmountController'; +export { NotificationsFeedManager } from '@multiversx/sdk-dapp/out/managers/NotificationsFeedManager/NotificationsFeedManager'; +export { TransactionManager } from '@multiversx/sdk-dapp/out/managers/TransactionManager'; +export { TransactionsTableController } from '@multiversx/sdk-dapp/out/controllers/TransactionsTableController'; +export { UnlockPanelManager } from '@multiversx/sdk-dapp/out/managers/UnlockPanelManager'; +export { WALLET_PROVIDER_SEND_TRANSACTION_URL } from '@multiversx/sdk-dapp/out/constants/webWalletProvider.constants'; +export { getAccountProvider } from '@multiversx/sdk-dapp/out/providers/helpers/accountProvider'; +export { getActiveTransactionsStatus } from '@multiversx/sdk-dapp/out/utils/transactions/getActiveTransactionsStatus'; +export { getExplorerLink } from '@multiversx/sdk-dapp/out/utils/transactions/getExplorerLink'; +export { getInterpretedTransaction } from '@multiversx/sdk-dapp/out/utils/transactions/getInterpretedTransaction'; +export { getTransactions } from '@multiversx/sdk-dapp/out/apiCalls/transactions/getTransactions'; +export { initApp } from '@multiversx/sdk-dapp/out/methods/initApp/initApp'; +export { setAxiosInterceptors } from '@multiversx/sdk-dapp/out/utils/network/setAxiosInterceptors'; +export { signTransactions } from '@multiversx/sdk-dapp/out/providers/strategies/helpers/signTransactions/signTransactions'; +export { trimUsernameDomain } from '@multiversx/sdk-dapp/out/utils/account/trimUsernameDomain'; diff --git a/src/lib/sdkDapp/sdkDapp.hooks.ts b/src/lib/sdkDapp/sdkDapp.hooks.ts index 0dffc93a..eab4bf67 100644 --- a/src/lib/sdkDapp/sdkDapp.hooks.ts +++ b/src/lib/sdkDapp/sdkDapp.hooks.ts @@ -1,21 +1,6 @@ -export { useBatchTransactionsTracker } from '@multiversx/sdk-dapp/hooks/transactions/batch/tracker/useBatchTransactionsTracker'; -export { useCheckBatch } from '@multiversx/sdk-dapp/hooks/transactions/batch/tracker/useCheckBatch'; -export { useGetAccount } from '@multiversx/sdk-dapp/hooks/account/useGetAccount'; -export { useGetAccountInfo } from '@multiversx/sdk-dapp/hooks/account/useGetAccountInfo'; -export { useGetAccountProvider } from '@multiversx/sdk-dapp/hooks/account/useGetAccountProvider'; -export { useGetActiveTransactionsStatus } from '@multiversx/sdk-dapp/hooks/transactions/useGetActiveTransactionsStatus'; -export { useGetBatches } from '@multiversx/sdk-dapp/hooks/transactions/batch/useGetBatches'; -export { useGetIsLoggedIn } from '@multiversx/sdk-dapp/hooks/account/useGetIsLoggedIn'; -export { useGetLastSignedMessageSession } from '@multiversx/sdk-dapp/hooks/signMessage/useGetLastSignedMessageSession'; -export { useGetLoginInfo } from '@multiversx/sdk-dapp/hooks/account/useGetLoginInfo'; -export { useGetNetworkConfig } from '@multiversx/sdk-dapp/hooks/useGetNetworkConfig'; -export { useGetPendingTransactions } from '@multiversx/sdk-dapp/hooks/transactions/useGetPendingTransactions'; -export { useGetSignMessageInfoStatus } from '@multiversx/sdk-dapp/hooks/signMessage/useGetSignedMessageStatus'; -export { useGetSignMessageSession } from '@multiversx/sdk-dapp/hooks/signMessage/useGetSignMessageSession'; -export { useGetSignedTransactions } from '@multiversx/sdk-dapp/hooks/transactions/useGetSignedTransactions'; -export { useParseSignedTransactions } from '@multiversx/sdk-dapp/hooks/transactions/useParseSignedTransactions'; -export { useSendBatchTransactions } from '@multiversx/sdk-dapp/hooks/transactions/batch/useSendBatchTransactions'; -export { useSignMessage } from '@multiversx/sdk-dapp/hooks/signMessage/useSignMessage'; -export { useSignTransactions } from '@multiversx/sdk-dapp/hooks/transactions/useSignTransactions'; -export { useTrackTransactionStatus } from '@multiversx/sdk-dapp/hooks/transactions/useTrackTransactionStatus'; -export { useTransactionsTracker } from '@multiversx/sdk-dapp/hooks/transactions/useTransactionsTracker'; +export { useGetAccount } from '@multiversx/sdk-dapp/out/react/account/useGetAccount'; +export { useGetAccountInfo } from '@multiversx/sdk-dapp/out/react/account/useGetAccountInfo'; +export { useGetIsLoggedIn } from '@multiversx/sdk-dapp/out/react/account/useGetIsLoggedIn'; +export { useGetLoginInfo } from '@multiversx/sdk-dapp/out/react/loginInfo/useGetLoginInfo'; +export { useGetNetworkConfig } from '@multiversx/sdk-dapp/out/react/network/useGetNetworkConfig'; +export { useGetPendingTransactions } from '@multiversx/sdk-dapp/out/react/transactions/useGetPendingTransactions'; diff --git a/src/lib/sdkDapp/sdkDapp.types.ts b/src/lib/sdkDapp/sdkDapp.types.ts index 853325b6..1395fe76 100644 --- a/src/lib/sdkDapp/sdkDapp.types.ts +++ b/src/lib/sdkDapp/sdkDapp.types.ts @@ -1,14 +1,9 @@ -export type { AccountType } from '@multiversx/sdk-dapp/types/account.types'; -export { - EnvironmentsEnum, - LoginMethodsEnum, - SignedMessageStatusesEnum -} from '@multiversx/sdk-dapp/types/enums.types'; -export type { - RawTransactionType, - SignedTransactionType, - TransactionsDisplayInfoType -} from '@multiversx/sdk-dapp/types/transactions.types'; -export type { RouteType } from '@multiversx/sdk-dapp/types/index'; -export type { ServerTransactionType } from '@multiversx/sdk-dapp/types/serverTransactions.types'; -export { TransactionBatchStatusesEnum } from '@multiversx/sdk-dapp/types/enums.types'; +export type { AccountType } from '@multiversx/sdk-dapp/out/types/account.types'; +export { EnvironmentsEnum } from '@multiversx/sdk-dapp/out/types/enums.types'; +export type { ICustomProvider } from '@multiversx/sdk-dapp/out/providers/types/providerFactory.types'; +export type { IProvider } from '@multiversx/sdk-dapp/out/providers/types/providerFactory.types'; +export type { InitAppType } from '@multiversx/sdk-dapp/out/methods/initApp/initApp.types'; +export type { ServerTransactionType } from '@multiversx/sdk-dapp/out/types/serverTransactions.types'; +export type { SignedTransactionType } from '@multiversx/sdk-dapp/out/types/transactions.types'; +export type { TransactionsDisplayInfoType } from '@multiversx/sdk-dapp/out/types/transactions.types'; +export type { TransactionsRowType } from '@multiversx/sdk-dapp/out/controllers/TransactionsTableController/transactionsTableController.types'; diff --git a/src/lib/sdkDappUI/index.ts b/src/lib/sdkDappUI/index.ts new file mode 100644 index 00000000..3f099713 --- /dev/null +++ b/src/lib/sdkDappUI/index.ts @@ -0,0 +1,2 @@ +export * from './sdkDappUI.components'; +export * from './sdkDappUI.types'; diff --git a/src/lib/sdkDappUI/sdkDappUI.components.ts b/src/lib/sdkDappUI/sdkDappUI.components.ts new file mode 100644 index 00000000..ec5d3e68 --- /dev/null +++ b/src/lib/sdkDappUI/sdkDappUI.components.ts @@ -0,0 +1,7 @@ +export { + MvxCopyButton, + MvxExplorerLink, + MvxFormatAmount, + MvxTransactionsTable, + MvxUnlockButton +} from '@multiversx/sdk-dapp-ui/react'; diff --git a/src/lib/sdkDappUI/sdkDappUI.types.ts b/src/lib/sdkDappUI/sdkDappUI.types.ts new file mode 100644 index 00000000..64af950b --- /dev/null +++ b/src/lib/sdkDappUI/sdkDappUI.types.ts @@ -0,0 +1,3 @@ +export type { MvxCopyButton as MvxCopyButtonPropsType } from '@multiversx/sdk-dapp-ui/web-components/mvx-copy-button'; +export type { MvxExplorerLink as MvxExplorerLinkPropsType } from '@multiversx/sdk-dapp-ui/web-components/mvx-explorer-link'; +export type { MvxFormatAmount as MvxFormatAmountPropsType } from '@multiversx/sdk-dapp-ui/web-components/mvx-format-amount'; diff --git a/src/lib/sdkDappUtils/index.ts b/src/lib/sdkDappUtils/index.ts new file mode 100644 index 00000000..5e18c9ec --- /dev/null +++ b/src/lib/sdkDappUtils/index.ts @@ -0,0 +1,2 @@ +export * from './sdkDappUtils'; +export * from './sdkDappUtils.types'; diff --git a/src/lib/sdkDappUtils/sdkDappUtils.ts b/src/lib/sdkDappUtils/sdkDappUtils.ts new file mode 100644 index 00000000..53640edd --- /dev/null +++ b/src/lib/sdkDappUtils/sdkDappUtils.ts @@ -0,0 +1,3 @@ +export { DECIMALS, DIGITS } from '@multiversx/sdk-dapp-utils/out/constants'; +export { formatAmount } from '@multiversx/sdk-dapp-utils/out/helpers/formatAmount'; +export { parseAmount } from '@multiversx/sdk-dapp-utils/out/helpers/parseAmount'; diff --git a/src/lib/sdkDappUtils/sdkDappUtils.types.ts b/src/lib/sdkDappUtils/sdkDappUtils.types.ts new file mode 100644 index 00000000..f72bbee0 --- /dev/null +++ b/src/lib/sdkDappUtils/sdkDappUtils.types.ts @@ -0,0 +1 @@ +export type { IDAppProviderAccount } from '@multiversx/sdk-dapp-utils/out/models'; diff --git a/src/localConstants/index.ts b/src/localConstants/index.ts index be49925f..ace81441 100644 --- a/src/localConstants/index.ts +++ b/src/localConstants/index.ts @@ -1,4 +1,3 @@ export * from './dataTestIds.enum'; export * from './routes'; -export * from './session'; export * from './signMessage'; diff --git a/src/localConstants/session/index.ts b/src/localConstants/session/index.ts deleted file mode 100644 index 82def9ba..00000000 --- a/src/localConstants/session/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './session.enums'; - -export const isSafari = /^((?!chrome|android).)*safari/i.test( - navigator.userAgent -); diff --git a/src/localConstants/session/session.enums.ts b/src/localConstants/session/session.enums.ts deleted file mode 100644 index 38228a12..00000000 --- a/src/localConstants/session/session.enums.ts +++ /dev/null @@ -1,8 +0,0 @@ -export enum SessionEnum { - batchSessionId = 'batchSessionId', - signedSessionId = 'signedSessionId', - rawPingPongSessionId = 'rawPingPongSessionId', - abiPingPongSessionId = 'abiPingPongSessionId', - abiPingPongServiceSessionId = 'abiPingPongServiceSessionId', - batchId = 'batchId' -} diff --git a/src/pages/Dashboard/Dashboard.tsx b/src/pages/Dashboard/Dashboard.tsx index e61553e5..8bc779f9 100644 --- a/src/pages/Dashboard/Dashboard.tsx +++ b/src/pages/Dashboard/Dashboard.tsx @@ -1,5 +1,4 @@ import { contractAddress } from 'config'; -import { useScrollToElement } from 'hooks'; import { WidgetType } from 'types/widget.types'; import { Widget } from './components'; import { @@ -26,8 +25,7 @@ const WIDGETS: WidgetType[] = [ description: 'Smart Contract interactions using manually formulated transactions', reference: - 'https://docs.multiversx.com/sdk-and-tools/indices/es-index-transactions/', - anchor: 'ping-pong-manual' + 'https://docs.multiversx.com/sdk-and-tools/indices/es-index-transactions/' }, { title: 'Ping & Pong (ABI)', @@ -35,23 +33,20 @@ const WIDGETS: WidgetType[] = [ description: 'Smart Contract interactions using the ABI generated transactions', reference: - 'https://docs.multiversx.com/sdk-and-tools/sdk-js/sdk-js-cookbook/#using-interaction-when-the-abi-is-available', - anchor: 'ping-pong-abi' + 'https://docs.multiversx.com/sdk-and-tools/sdk-js/sdk-js-cookbook/#using-interaction-when-the-abi-is-available' }, { title: 'Ping & Pong (Backend)', widget: PingPongService, description: 'Smart Contract interactions using the backend generated transactions', - reference: 'https://github.com/multiversx/mx-ping-pong-service', - anchor: 'ping-pong-backend' + reference: 'https://github.com/multiversx/mx-ping-pong-service' }, { title: 'Sign message', widget: SignMessage, description: 'Message signing using the connected account', - reference: 'https://docs.multiversx.com/sdk-and-tools/sdk-dapp/#account-1', - anchor: 'sign-message' + reference: 'https://docs.multiversx.com/sdk-and-tools/sdk-dapp/#account-1' }, { title: 'Native auth', @@ -66,8 +61,7 @@ const WIDGETS: WidgetType[] = [ description: 'For complex scenarios transactions can be sent in the desired group/sequence', reference: - 'https://github.com/multiversx/mx-sdk-dapp#sending-transactions-synchronously-in-batches', - anchor: 'batch-transactions' + 'https://github.com/multiversx/mx-sdk-dapp#sending-transactions-synchronously-in-batches' }, { title: 'Transactions (All)', @@ -87,8 +81,6 @@ const WIDGETS: WidgetType[] = [ ]; export const Dashboard = () => { - useScrollToElement(); - return (
{WIDGETS.map((element) => ( diff --git a/src/pages/Dashboard/components/Widget.tsx b/src/pages/Dashboard/components/Widget.tsx index 3177d7b5..9b7a7a90 100644 --- a/src/pages/Dashboard/components/Widget.tsx +++ b/src/pages/Dashboard/components/Widget.tsx @@ -1,7 +1,5 @@ import { Card } from 'components'; -import { useIsWebProvider } from 'hooks'; import { WidgetType } from 'types/widget.types'; -import { getCallbackRoute } from 'utils/getCallbackRoute'; export const Widget = ({ title, @@ -11,11 +9,6 @@ export const Widget = ({ widget: MxWidget, props = {} }: WidgetType) => { - const { isWebProvider } = useIsWebProvider(); - const callbackRoute = anchor - ? getCallbackRoute({ anchor, isWebProvider }) - : ''; - return ( - + ); }; diff --git a/src/pages/Dashboard/widgets/Account/Account.tsx b/src/pages/Dashboard/widgets/Account/Account.tsx index 800e9b1a..ffeb1f84 100644 --- a/src/pages/Dashboard/widgets/Account/Account.tsx +++ b/src/pages/Dashboard/widgets/Account/Account.tsx @@ -1,12 +1,26 @@ import { Label, OutputContainer } from 'components'; -import { FormatAmount, useGetAccountInfo, useGetNetworkConfig } from 'lib'; -import { DataTestIdsEnum } from 'localConstants'; +import { + DECIMALS, + DIGITS, + FormatAmountController, + MvxFormatAmount, + useGetAccountInfo, + useGetNetworkConfig +} from 'lib'; import { Username } from './components'; export const Account = () => { const { network } = useGetNetworkConfig(); const { address, account } = useGetAccountInfo(); + const { isValid, valueDecimal, valueInteger, label } = + FormatAmountController.getData({ + digits: DIGITS, + decimals: DECIMALS, + egldLabel: network.egldLabel, + input: account.balance + }); + return (
@@ -22,10 +36,13 @@ export const Account = () => {

-

diff --git a/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx b/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx index 3e61b578..0db48c91 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx +++ b/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx @@ -3,106 +3,57 @@ import { faPaperPlane } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useEffect, useState } from 'react'; import { Button, OutputContainer, TransactionsOutput } from 'components'; import { - useGetAccountInfo, - useGetBatches, + useGetAccount, useGetNetworkConfig, useGetPendingTransactions } from 'lib'; -import { SessionEnum } from 'localConstants/session'; -import { SignedTransactionType, WidgetProps } from 'types'; -import { useBatchTransactionContext } from 'wrappers'; import { sendBatchTransactions, signAndAutoSendBatchTransactions, swapAndLockTokens } from './helpers'; -import { useSendSignedTransactions } from './hooks'; -export const BatchTransactions = ({ callbackRoute }: WidgetProps) => { - const { setSendBatchTransactionsOnDemand } = useBatchTransactionContext(); - const { address, account } = useGetAccountInfo(); +export const BatchTransactions = () => { + const { address, nonce } = useGetAccount(); const { network } = useGetNetworkConfig(); - const { batches } = useGetBatches(); - const { hasPendingTransactions } = useGetPendingTransactions(); - const [trackBatchId, setTrackBatchId] = useState( - sessionStorage.getItem(SessionEnum.batchId) - ); - - const [stateTransactions, setStateTransactions] = useState< - SignedTransactionType[] | null - >(null); - const [currentSessionId, setCurrentSessionId] = useState( - sessionStorage.getItem(SessionEnum.signedSessionId) || '' - ); - - const { batchId, setBatchSessionId } = useSendSignedTransactions({ - signedSessionId: currentSessionId - }); - - // If manual batch transactions are executed, track the batchId - useEffect(() => { - if (batchId) { - setTrackBatchId(batchId); - } - }, [batchId]); - - useEffect(() => { - if (trackBatchId && batches[trackBatchId]) { - setStateTransactions(batches[trackBatchId].transactions.flat()); - } - }, [trackBatchId, batches]); + const transactions = useGetPendingTransactions(); + const hasPendingTransactions = transactions.length > 0; const executeSignAndAutoSendBatchTransactions = async () => { - setSendBatchTransactionsOnDemand(false); - - const { batchId: batchIdResult } = await signAndAutoSendBatchTransactions({ + await signAndAutoSendBatchTransactions({ address, - nonce: account.nonce, + nonce, chainID: network.chainId, - callbackRoute + transactionsDisplayInfo: { + processingMessage: 'Processing batch transactions', + errorMessage: + 'An error has occurred during batch transaction execution', + successMessage: 'Batch transactions successful' + } }); - - if (!batchIdResult) { - return; - } - - setTrackBatchId(batchIdResult); }; const executeBatchTransactions = async () => { - setSendBatchTransactionsOnDemand(true); - const { newBatchSessionId, sessionId } = await sendBatchTransactions({ + await sendBatchTransactions({ address, - nonce: account.nonce, - chainID: network.chainId, - callbackRoute + nonce, + chainID: network.chainId }); - - if (!newBatchSessionId || !sessionId) { - return; - } - - setBatchSessionId(newBatchSessionId); - setCurrentSessionId(sessionId); }; const executeSwapAndLockTokens = async () => { - setSendBatchTransactionsOnDemand(true); - const { batchId: currentBatchId } = await swapAndLockTokens({ + await swapAndLockTokens({ address, - nonce: account.nonce, + nonce, chainID: network.chainId, - callbackRoute + transactionsDisplayInfo: { + processingMessage: 'Processing swap and lock', + errorMessage: 'An error has occurred during swap and lock', + successMessage: 'Swap and lock successful' + } }); - - if (!currentBatchId) { - return; - } - - setTrackBatchId(currentBatchId); }; return ( @@ -124,7 +75,6 @@ export const BatchTransactions = ({ callbackRoute }: WidgetProps) => { Sign batch & controlled sending -
- {stateTransactions && ( - - )} +
); diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts index b1dcc856..9aa6e7cf 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts @@ -1,41 +1,32 @@ +import BigNumber from 'bignumber.js'; import { - DECIMALS, - EXTRA_GAS_LIMIT_GUARDED_TX, - GAS_LIMIT, - GAS_PRICE, - newTransaction, - TokenTransfer, + Address, Transaction, - VERSION + TransactionsFactoryConfig, + TransferTransactionsFactory } from 'lib'; -import { TransactionProps } from 'types/transaction.types'; +import { TransactionProps } from 'types'; const NUMBER_OF_TRANSACTIONS = 5; export const getBatchTransactions = ({ address, - nonce, chainID }: TransactionProps): Transaction[] => { const transactions = Array.from(Array(NUMBER_OF_TRANSACTIONS).keys()); + const factoryConfig = new TransactionsFactoryConfig({ chainID }); + const factory = new TransferTransactionsFactory({ config: factoryConfig }); + return transactions.map((id) => { - const amount = TokenTransfer.fungibleFromAmount( - '', - id + 1, - DECIMALS - ).toString(); + const tokenTransfer = factory.createTransactionForNativeTokenTransfer( + Address.newFromBech32(address), + { + receiver: Address.newFromBech32(address), + nativeAmount: BigInt(new BigNumber(id).plus(1).shiftedBy(18).toFixed()) + } + ); - return newTransaction({ - sender: address, - receiver: address, - data: `batch-tx-${id + 1}`, - value: amount, - chainID, - gasLimit: GAS_LIMIT + EXTRA_GAS_LIMIT_GUARDED_TX, - gasPrice: GAS_PRICE, - nonce, - version: VERSION - }); + return tokenTransfer; }); }; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getSwapAndLockTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getSwapAndLockTransactions.ts index 0c15d064..4393ec37 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getSwapAndLockTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getSwapAndLockTransactions.ts @@ -1,5 +1,5 @@ import { BATCH_TRANSACTIONS_SC } from 'config'; -import { GAS_PRICE, newTransaction, Transaction, VERSION } from 'lib'; +import { Address, GAS_PRICE, Transaction, VERSION } from 'lib'; import { TransactionProps } from 'types'; export const getSwapAndLockTransactions = ({ @@ -8,49 +8,53 @@ export const getSwapAndLockTransactions = ({ nonce }: TransactionProps): Transaction[] => { return [ - newTransaction({ + new Transaction({ chainID, - gasLimit: 4200000, - gasPrice: GAS_PRICE, - nonce, - receiver: BATCH_TRANSACTIONS_SC.egld_wEGLD.contract, - sender: address, - value: '1000000000000000000', + gasLimit: BigInt(4200000), + gasPrice: BigInt(GAS_PRICE), + nonce: BigInt(nonce), + receiver: Address.newFromBech32( + BATCH_TRANSACTIONS_SC.egld_wEGLD.contract + ), + sender: Address.newFromBech32(address), + value: BigInt('1000000000000000000'), version: VERSION, - data: BATCH_TRANSACTIONS_SC.egld_wEGLD.data + data: Uint8Array.from(Buffer.from(BATCH_TRANSACTIONS_SC.egld_wEGLD.data)) }), - newTransaction({ + new Transaction({ chainID, - gasLimit: 25500000, - gasPrice: GAS_PRICE, - nonce, - receiver: BATCH_TRANSACTIONS_SC.wEGLD_USDC.contract, - sender: address, - value: '0', + gasLimit: BigInt(25500000), + gasPrice: BigInt(GAS_PRICE), + nonce: BigInt(nonce), + receiver: Address.newFromBech32( + BATCH_TRANSACTIONS_SC.wEGLD_USDC.contract + ), + sender: Address.newFromBech32(address), + value: BigInt('0'), version: VERSION, - data: BATCH_TRANSACTIONS_SC.wEGLD_USDC.data + data: Uint8Array.from(Buffer.from(BATCH_TRANSACTIONS_SC.wEGLD_USDC.data)) }), - newTransaction({ + new Transaction({ chainID, - gasLimit: 25500000, - gasPrice: GAS_PRICE, - nonce, - receiver: BATCH_TRANSACTIONS_SC.wEGLD_MEX.contract, - sender: address, - value: '0', + gasLimit: BigInt(25500000), + gasPrice: BigInt(GAS_PRICE), + nonce: BigInt(nonce), + receiver: Address.newFromBech32(BATCH_TRANSACTIONS_SC.wEGLD_MEX.contract), + sender: Address.newFromBech32(address), + value: BigInt('0'), version: VERSION, - data: BATCH_TRANSACTIONS_SC.wEGLD_MEX.data + data: Uint8Array.from(Buffer.from(BATCH_TRANSACTIONS_SC.wEGLD_MEX.data)) }), - newTransaction({ + new Transaction({ chainID, - gasLimit: 10000000, - gasPrice: GAS_PRICE, - nonce, - receiver: BATCH_TRANSACTIONS_SC.lock_MEX.contract, - sender: address, - value: '0', + gasLimit: BigInt(10000000), + gasPrice: BigInt(GAS_PRICE), + nonce: BigInt(nonce), + receiver: Address.newFromBech32(BATCH_TRANSACTIONS_SC.lock_MEX.contract), + sender: Address.newFromBech32(address), + value: BigInt('0'), version: VERSION, - data: BATCH_TRANSACTIONS_SC.lock_MEX.data + data: Uint8Array.from(Buffer.from(BATCH_TRANSACTIONS_SC.lock_MEX.data)) }) ]; }; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendAndTrackTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendAndTrackTransactions.ts new file mode 100644 index 00000000..0ee3fda0 --- /dev/null +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendAndTrackTransactions.ts @@ -0,0 +1,25 @@ +import { + Transaction, + TransactionManager, + TransactionsDisplayInfoType +} from 'lib'; + +type SendAndTrackTransactionsType = { + transactions: Transaction[] | Transaction[][]; + options?: { + disableToasts?: boolean; + transactionsDisplayInfo?: TransactionsDisplayInfoType; + }; +}; + +export const sendAndTrackTransactions = async ({ + transactions, + options +}: SendAndTrackTransactionsType) => { + const txManager = TransactionManager.getInstance(); + + const sentTransactions = await txManager.send(transactions); + const sessionId = await txManager.track(sentTransactions, options); + + return sessionId; +}; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendBatchTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendBatchTransactions.ts index dedb0830..9f29cdde 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendBatchTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/sendBatchTransactions.ts @@ -1,38 +1,32 @@ -import { sendTransactions } from 'lib/sdkDapp/sdkDapp.helpers'; -import { isSafari, SessionEnum } from 'localConstants/session'; -import { getBatchTransactions } from '../helpers'; -import { SendTransactionProps } from '../types'; +import { getAccountProvider } from 'lib'; +import { TransactionProps } from 'types'; +import { getBatchTransactions } from './getBatchTransactions'; +import { sendAndTrackTransactions } from './sendAndTrackTransactions'; export const sendBatchTransactions = async ({ address, chainID, - nonce, - callbackRoute -}: SendTransactionProps) => { - const transactions = getBatchTransactions({ + nonce +}: TransactionProps) => { + const provider = getAccountProvider(); + + const transactionsToSign = getBatchTransactions({ address, chainID, nonce }); - const { sessionId, error } = await sendTransactions({ - transactions, - signWithoutSending: true, - customTransactionInformation: { redirectAfterSign: true }, - callbackRoute, - hasConsentPopup: isSafari - }); + const transactions = await provider.signTransactions(transactionsToSign); - if (error) { - console.error('Could not execute transactions', error); - return {}; - } + const groupedTransactions = [ + [transactions[0]], + [transactions[1], transactions[2]], + [transactions[3], transactions[4]] + ]; - const newBatchSessionId = Date.now().toString(); - // sdk-dapp by default takes the last session id from sdk-dapp’s redux store on page refresh - // in order to differentiate the transactions between widgets, a persistence of sessionId is needed - sessionStorage.setItem(SessionEnum.batchSessionId, newBatchSessionId); - sessionStorage.setItem(SessionEnum.signedSessionId, sessionId); + const sessionId = await sendAndTrackTransactions({ + transactions: groupedTransactions + }); - return { newBatchSessionId, sessionId }; + return sessionId; }; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts index 8d1b8ea2..8140cb16 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts @@ -1,47 +1,42 @@ -import { refreshAccount, sendBatchTransactions } from 'lib'; -import { isSafari, SessionEnum } from 'localConstants/session'; -import { getBatchTransactions } from '../helpers'; -import { SendTransactionProps } from '../types'; +import { getAccountProvider, TransactionsDisplayInfoType } from 'lib'; +import { TransactionProps } from 'types'; +import { getBatchTransactions } from './getBatchTransactions'; +import { sendAndTrackTransactions } from './sendAndTrackTransactions'; -// this process will not go through useSendSignedTransactions -// it will automatically sign and send transactions export const signAndAutoSendBatchTransactions = async ({ address, nonce, chainID, - callbackRoute -}: SendTransactionProps) => { + transactionsDisplayInfo = { + processingMessage: 'Processing transactions', + errorMessage: 'An error has occurred during transaction execution', + successMessage: 'Batch transactions successful' + } +}: TransactionProps & { + transactionsDisplayInfo?: TransactionsDisplayInfoType; +}) => { + const provider = getAccountProvider(); + const transactions = getBatchTransactions({ address, nonce, chainID }); + const signedTransactions = await provider.signTransactions(transactions); + const groupedTransactions = [ - [transactions[0]], - [transactions[1], transactions[2]], - [transactions[3], transactions[4]] + [signedTransactions[0]], + [signedTransactions[1], signedTransactions[2]], + [signedTransactions[3], signedTransactions[4]] ]; - await refreshAccount(); - - const { batchId, error } = await sendBatchTransactions({ + const sessionId = await sendAndTrackTransactions({ transactions: groupedTransactions, - customTransactionInformation: { redirectAfterSign: true }, - transactionsDisplayInfo: { - processingMessage: 'Processing transactions', - errorMessage: 'An error has occurred during transaction execution', - successMessage: 'Batch transactions successful' - }, - callbackRoute, - hasConsentPopup: isSafari + options: { + transactionsDisplayInfo + } }); - if (error) { - console.error('Could not execute transactions', error); - return {}; - } - - sessionStorage.setItem(SessionEnum.batchId, batchId); - return { batchId }; + return sessionId; }; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts index 2454718b..165a6527 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts @@ -1,46 +1,42 @@ -import { refreshAccount, sendBatchTransactions } from 'lib'; -import { isSafari, SessionEnum } from 'localConstants/session'; -import { getSwapAndLockTransactions } from '../helpers'; -import { SendTransactionProps } from '../types'; +import { getAccountProvider, TransactionsDisplayInfoType } from 'lib'; +import { TransactionProps } from 'types'; +import { getSwapAndLockTransactions } from './getSwapAndLockTransactions'; +import { sendAndTrackTransactions } from './sendAndTrackTransactions'; export const swapAndLockTokens = async ({ address, nonce, chainID, - callbackRoute -}: SendTransactionProps) => { - const transactions = getSwapAndLockTransactions({ + transactionsDisplayInfo = { + processingMessage: 'Processing transactions', + errorMessage: 'An error has occurred during transaction execution', + successMessage: 'Swap and lock transactions successful' + } +}: TransactionProps & { + transactionsDisplayInfo?: TransactionsDisplayInfoType; +}) => { + const provider = getAccountProvider(); + + const transactionsToSign = getSwapAndLockTransactions({ address, chainID, nonce }); + const transactions = await provider.signTransactions(transactionsToSign); + const groupedTransactions = [ [transactions[0]], [transactions[1], transactions[2]], [transactions[3]] ]; - await refreshAccount(); - - const { batchId, error } = await sendBatchTransactions({ + const sessionId = await sendAndTrackTransactions({ transactions: groupedTransactions, - customTransactionInformation: { redirectAfterSign: true }, - transactionsDisplayInfo: { - processingMessage: 'Processing transactions', - errorMessage: 'An error has occurred during transaction execution', - successMessage: 'Batch transactions successful' - }, - callbackRoute, - hasConsentPopup: isSafari + options: { + transactionsDisplayInfo + } }); - if (error) { - console.error('Could not execute transactions', error); - return {}; - } - - sessionStorage.setItem(SessionEnum.batchId, batchId); - - return { batchId }; + return sessionId; }; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/hooks/index.ts b/src/pages/Dashboard/widgets/BatchTransactions/hooks/index.ts deleted file mode 100644 index e60e6be1..00000000 --- a/src/pages/Dashboard/widgets/BatchTransactions/hooks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './useSendSignedTransactions'; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/hooks/useSendSignedTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/hooks/useSendSignedTransactions.ts deleted file mode 100644 index 8e001544..00000000 --- a/src/pages/Dashboard/widgets/BatchTransactions/hooks/useSendSignedTransactions.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { useEffect, useState } from 'react'; -import { - deleteTransactionToast, - removeAllSignedTransactions, - removeAllTransactionsToSign, - setTransactionsDisplayInfoState, - setTransactionsToSignedState, - TransactionBatchStatusesEnum, - useGetSignedTransactions, - useSendBatchTransactions -} from 'lib'; -import { SessionEnum } from 'localConstants'; -import { useBatchTransactionContext } from 'wrappers'; - -export const useSendSignedTransactions = ({ - signedSessionId = '' -}: { - signedSessionId: string; -}) => { - const [batchSessionId, setBatchSessionId] = useState( - sessionStorage.getItem(SessionEnum.batchSessionId) - ); - const { signedTransactions } = useGetSignedTransactions(); - const { send: sendBatchToBlockchain, batchId } = useSendBatchTransactions(); - const { sendBatchTransactionsOnDemand } = useBatchTransactionContext(); - - const clearTransactionsInformation = () => { - removeAllSignedTransactions(); - removeAllTransactionsToSign(); - deleteTransactionToast(batchSessionId ?? ''); - sessionStorage.removeItem(SessionEnum.batchSessionId); - setBatchSessionId(null); - }; - - const sendTransactions = async () => { - if (!batchSessionId || !signedSessionId) { - return; - } - - const signedSession = signedTransactions?.[signedSessionId]; - const signedSessionTransactions = signedSession?.transactions; - - if (!signedSession || signedSessionTransactions?.length === 0) { - return; - } - - // Cancel flow - if (signedSession?.status !== TransactionBatchStatusesEnum.signed) { - clearTransactionsInformation(); - return; - } - - setTransactionsToSignedState({ - sessionId: batchSessionId, - status: TransactionBatchStatusesEnum.signed, - transactions: signedSessionTransactions - }); - - // In order to reuse the current flow for batch transactions in sdk-dapp we need to use this function - // in order to set the toast display info because the last signed sessionId is not used anymore - // but the new sessionId from the batchId is used - setTransactionsDisplayInfoState({ - sessionId: batchSessionId, - transactionsDisplayInfo: { - processingMessage: 'Processing transactions', - errorMessage: 'An error has occurred during transaction execution', - successMessage: 'Batch transactions successful' - } - }); - - const { error } = await sendBatchToBlockchain({ - transactions: [signedSessionTransactions], - sessionId: batchSessionId - }); - - setBatchSessionId(null); - sessionStorage.removeItem(SessionEnum.batchSessionId); - - if (error) { - clearTransactionsInformation(); - console.log('Failed to send batch', batchSessionId); - } - }; - - const status = signedTransactions[signedSessionId]?.status; - - useEffect(() => { - if (!sendBatchTransactionsOnDemand) { - return; - } - - if (!batchSessionId) { - return; - } - - if (status === TransactionBatchStatusesEnum.signed) { - sendTransactions(); - } - }, [batchSessionId, status]); - - return { - batchId, - setBatchSessionId - }; -}; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/types.ts b/src/pages/Dashboard/widgets/BatchTransactions/types.ts deleted file mode 100644 index 0d3c5070..00000000 --- a/src/pages/Dashboard/widgets/BatchTransactions/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { TransactionProps } from 'types/transaction.types'; - -export type SendTransactionProps = TransactionProps & { - callbackRoute: string; -}; diff --git a/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx b/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx index 391ded92..1e3dccd6 100644 --- a/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx +++ b/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx @@ -1,6 +1,13 @@ import { useEffect } from 'react'; import { Label, MissingNativeAuthError, OutputContainer } from 'components'; -import { FormatAmount, useGetLoginInfo, useGetNetworkConfig } from 'lib'; +import { + DECIMALS, + DIGITS, + FormatAmountController, + MvxFormatAmount, + useGetLoginInfo, + useGetNetworkConfig +} from 'lib'; import { Username } from '../Account/components'; import { useGetProfile } from './hooks'; @@ -8,6 +15,13 @@ export const NativeAuth = () => { const { tokenLogin, isLoggedIn } = useGetLoginInfo(); const { isLoading, profile, getProfile } = useGetProfile(); const { network } = useGetNetworkConfig(); + const { isValid, valueDecimal, valueInteger, label } = + FormatAmountController.getData({ + digits: DIGITS, + decimals: DECIMALS, + egldLabel: network.egldLabel, + input: profile?.balance ?? '0' + }); useEffect(() => { // On page refresh, tokenInfo is null which implies that we do not have access to loginInfo data @@ -43,10 +57,11 @@ export const NativeAuth = () => {
-
diff --git a/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx b/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx index 77cbae22..2ce6e3d2 100644 --- a/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx +++ b/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx @@ -12,26 +12,18 @@ import { import { getCountdownSeconds, setTimeRemaining } from 'helpers'; import { useSendPingPongTransaction } from 'hooks'; import { useGetPendingTransactions } from 'lib'; -import { SessionEnum } from 'localConstants'; -import { SignedTransactionType, WidgetProps } from 'types'; import { useGetPingAmount, useGetTimeToPong } from './hooks'; -export const PingPongAbi = ({ callbackRoute }: WidgetProps) => { - const { hasPendingTransactions } = useGetPendingTransactions(); +export const PingPongAbi = () => { + const transactions = useGetPendingTransactions(); + const hasPendingTransactions = transactions.length > 0; + const getTimeToPong = useGetTimeToPong(); - const { - sendPingTransactionFromAbi, - sendPongTransactionFromAbi, - transactionStatus - } = useSendPingPongTransaction({ - type: SessionEnum.abiPingPongSessionId - }); + const { sendPingTransactionFromAbi, sendPongTransactionFromAbi } = + useSendPingPongTransaction(); const pingAmount = useGetPingAmount(); - const [stateTransactions, setStateTransactions] = useState< - SignedTransactionType[] | null - >(null); - const [hasPing, setHasPing] = useState(true); + const [hasPing, setHasPing] = useState(true); const [secondsLeft, setSecondsLeft] = useState(0); const setSecondsRemaining = async () => { @@ -45,11 +37,11 @@ export const PingPongAbi = ({ callbackRoute }: WidgetProps) => { }; const onSendPingTransaction = async () => { - await sendPingTransactionFromAbi({ amount: pingAmount, callbackRoute }); + await sendPingTransactionFromAbi(pingAmount); }; const onSendPongTransaction = async () => { - await sendPongTransactionFromAbi({ callbackRoute }); + await sendPongTransactionFromAbi(); }; const timeRemaining = moment() @@ -63,12 +55,6 @@ export const PingPongAbi = ({ callbackRoute }: WidgetProps) => { getCountdownSeconds({ secondsLeft, setSecondsLeft }); }, [hasPing]); - useEffect(() => { - if (transactionStatus.transactions) { - setStateTransactions(transactionStatus.transactions); - } - }, [transactionStatus]); - useEffect(() => { setSecondsRemaining(); }, [hasPendingTransactions]); @@ -102,7 +88,7 @@ export const PingPongAbi = ({ callbackRoute }: WidgetProps) => { - {!stateTransactions && ( + {!hasPendingTransactions && ( <> {!pongAllowed && ( @@ -116,7 +102,7 @@ export const PingPongAbi = ({ callbackRoute }: WidgetProps) => { )} diff --git a/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx b/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx index e2299102..f02b679f 100644 --- a/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx +++ b/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx @@ -12,26 +12,21 @@ import { import { getCountdownSeconds, setTimeRemaining } from 'helpers'; import { useSendPingPongTransaction } from 'hooks'; import { useGetPendingTransactions } from 'lib'; -import { SignedTransactionType } from 'lib'; -import { SessionEnum } from 'localConstants'; -import { WidgetProps } from 'types'; import { useGetPingAmount, useGetTimeToPong } from './hooks'; // Raw transaction are being done by directly requesting to API instead of calling the smartcontract -export const PingPongRaw = ({ callbackRoute }: WidgetProps) => { +export const PingPongRaw = () => { const getTimeToPong = useGetTimeToPong(); - const { hasPendingTransactions } = useGetPendingTransactions(); - const { sendPingTransaction, sendPongTransaction, transactionStatus } = - useSendPingPongTransaction({ - type: SessionEnum.rawPingPongSessionId - }); + + const { sendPingTransaction, sendPongTransaction } = + useSendPingPongTransaction(); + + const transactions = useGetPendingTransactions(); + const hasPendingTransactions = transactions.length > 0; const pingAmount = useGetPingAmount(); - const [stateTransactions, setStateTransactions] = useState< - SignedTransactionType[] | null - >(null); - const [hasPing, setHasPing] = useState(true); - const [secondsLeft, setSecondsLeft] = useState(0); + const [hasPing, setHasPing] = useState(true); + const [secondsLeft, setSecondsLeft] = useState(0); const setSecondsRemaining = async () => { const secondsRemaining = await getTimeToPong(); @@ -44,11 +39,11 @@ export const PingPongRaw = ({ callbackRoute }: WidgetProps) => { }; const onSendPingTransaction = async () => { - await sendPingTransaction({ amount: pingAmount, callbackRoute }); + await sendPingTransaction(pingAmount); }; const onSendPongTransaction = async () => { - await sendPongTransaction({ callbackRoute }); + await sendPongTransaction(); }; const timeRemaining = moment() @@ -62,12 +57,6 @@ export const PingPongRaw = ({ callbackRoute }: WidgetProps) => { getCountdownSeconds({ secondsLeft, setSecondsLeft }); }, [hasPing]); - useEffect(() => { - if (transactionStatus.transactions) { - setStateTransactions(transactionStatus.transactions); - } - }, [transactionStatus]); - useEffect(() => { setSecondsRemaining(); }, [hasPendingTransactions]); @@ -99,7 +88,7 @@ export const PingPongRaw = ({ callbackRoute }: WidgetProps) => { - {!stateTransactions && ( + {!hasPendingTransactions && ( <> {!pongAllowed && ( @@ -112,7 +101,7 @@ export const PingPongRaw = ({ callbackRoute }: WidgetProps) => { )} diff --git a/src/pages/Dashboard/widgets/PingPongRaw/hooks/tests/useGetTimeToPong.test.ts b/src/pages/Dashboard/widgets/PingPongRaw/hooks/tests/useGetTimeToPong.test.ts deleted file mode 100644 index 85ca219e..00000000 --- a/src/pages/Dashboard/widgets/PingPongRaw/hooks/tests/useGetTimeToPong.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { renderHook } from '@testing-library/react'; -import axios from 'axios'; -import { useGetTimeToPong } from '../useGetTimeToPong'; - -beforeEach(() => { - jest.mock('@multiversx/sdk-dapp/hooks/useGetNetworkConfig', () => ({ - useGetNetworkConfig: jest.fn().mockReturnValue({ - network: { apiAddress: 'https://devnet-api.multiversx.com' } - }) - })); -}); - -describe('useGetTimeToPong', () => { - it('should return 180 seconds', async () => { - jest.spyOn(axios, 'post').mockResolvedValueOnce({ - data: { - data: { - data: { - returnData: ['tA=='] // 180 converted from b64 to hexa and from hexa to decimal - } - } - } - }); - - const { result } = renderHook(() => useGetTimeToPong()); - const timeToPong = await result.current(); - // Assert the result is correct based on your mock data - expect(timeToPong).toBe(180); - }); - - it('should return 0', async () => { - jest.spyOn(axios, 'post').mockResolvedValueOnce({ - data: { - data: { - data: { - returnData: [''] - } - } - } - }); - - const { result } = renderHook(() => useGetTimeToPong()); - const timeToPong = await result.current(); - // Assert the result is correct based on your mock data - expect(timeToPong).toBe(0); - }); - - it('should return null', async () => { - jest.spyOn(axios, 'post').mockResolvedValueOnce({ - data: { - data: { - data: { - returnData: [] - } - } - } - }); - - const { result } = renderHook(() => useGetTimeToPong()); - const timeToPong = await result.current(); - // Assert the result is correct based on your mock data - expect(timeToPong).toBe(null); - }); -}); diff --git a/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx b/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx index 725c8193..11be404c 100644 --- a/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx +++ b/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx @@ -13,8 +13,6 @@ import { import { getCountdownSeconds, setTimeRemaining } from 'helpers'; import { useSendPingPongTransaction } from 'hooks'; import { useGetLoginInfo, useGetPendingTransactions } from 'lib'; -import { SessionEnum } from 'localConstants'; -import { SignedTransactionType, WidgetProps } from 'types'; import { useGetPingTransaction, useGetPongTransaction, @@ -22,24 +20,18 @@ import { } from './hooks'; // The transactions are being done by directly requesting to template-dapp service -export const PingPongService = ({ callbackRoute }: WidgetProps) => { - const [stateTransactions, setStateTransactions] = useState< - SignedTransactionType[] | null - >(null); - const [hasPing, setHasPing] = useState(true); +export const PingPongService = () => { + const [hasPing, setHasPing] = useState(true); const [secondsLeft, setSecondsLeft] = useState(0); - const { - sendPingTransactionFromService, - sendPongTransactionFromService, - transactionStatus - } = useSendPingPongTransaction({ - type: SessionEnum.abiPingPongServiceSessionId - }); + const { sendPingTransactionFromService, sendPongTransactionFromService } = + useSendPingPongTransaction(); const getTimeToPong = useGetTimeToPong(); const getPingTransaction = useGetPingTransaction(); const getPongTransaction = useGetPongTransaction(); - const { hasPendingTransactions } = useGetPendingTransactions(); + const transactions = useGetPendingTransactions(); + const hasPendingTransactions = transactions.length > 0; + const { tokenLogin } = useGetLoginInfo(); const setSecondsRemaining = async () => { @@ -63,10 +55,7 @@ export const PingPongService = ({ callbackRoute }: WidgetProps) => { return; } - await sendPingTransactionFromService({ - transactions: [pingTransaction], - callbackRoute - }); + await sendPingTransactionFromService([pingTransaction]); }; const onSendPongTransaction = async () => { @@ -76,10 +65,7 @@ export const PingPongService = ({ callbackRoute }: WidgetProps) => { return; } - await sendPongTransactionFromService({ - transactions: [pongTransaction], - callbackRoute - }); + await sendPongTransactionFromService([pongTransaction]); }; const timeRemaining = moment() @@ -93,12 +79,6 @@ export const PingPongService = ({ callbackRoute }: WidgetProps) => { getCountdownSeconds({ secondsLeft, setSecondsLeft }); }, [hasPing]); - useEffect(() => { - if (transactionStatus.transactions) { - setStateTransactions(transactionStatus.transactions); - } - }, [transactionStatus]); - useEffect(() => { setSecondsRemaining(); }, [hasPendingTransactions]); @@ -134,7 +114,7 @@ export const PingPongService = ({ callbackRoute }: WidgetProps) => { - {!stateTransactions && ( + {!hasPendingTransactions && ( <> {!pongAllowed && ( @@ -147,7 +127,7 @@ export const PingPongService = ({ callbackRoute }: WidgetProps) => { )} diff --git a/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx b/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx index ff2f8fa9..d8048220 100644 --- a/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx +++ b/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx @@ -4,96 +4,102 @@ import { faFileSignature } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { MouseEvent } from 'react'; -import { useState } from 'react'; +import { MouseEvent, useState } from 'react'; import { Button, OutputContainer } from 'components'; -import { - SignedMessageStatusesEnum, - useGetSignMessageSession, - useSignMessage -} from 'lib'; -import { WidgetProps } from 'types'; +import { Address, getAccountProvider, Message, useGetAccount } from 'lib'; import { SignFailure, SignSuccess } from './components'; -export const SignMessage = ({ callbackRoute }: WidgetProps) => { - const { sessionId, signMessage, onAbort } = useSignMessage(); - const messageSession = useGetSignMessageSession(sessionId); - +export const SignMessage = () => { const [message, setMessage] = useState(''); + const [signedMessage, setSignedMessage] = useState(null); + const [state, setState] = useState<'pending' | 'success' | 'error'>( + 'pending' + ); - const handleSubmit = (e: MouseEvent) => { - e.preventDefault(); + const [signatrue, setSignatrue] = useState(''); + const { address } = useGetAccount(); + const provider = getAccountProvider(); - if (messageSession) { - onAbort(); - } + const handleSubmit = async () => { + try { + const messageToSign = new Message({ + address: new Address(address), + data: new Uint8Array(Buffer.from(message)) + }); - if (!message.trim()) { - return; - } + const signedMessageResult = await provider.signMessage(messageToSign); - signMessage({ - message, - callbackRoute - }); + if (!signedMessageResult?.signature) { + setState('error'); + return; + } - setMessage(''); + setState('success'); + setSignatrue(Buffer.from(signedMessageResult?.signature).toString('hex')); + setSignedMessage(signedMessageResult); + setMessage(''); + } catch (error) { + console.error(error); + setState('error'); + } }; const handleClear = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); - onAbort(); + setSignatrue(''); + setState('pending'); }; - const isError = messageSession - ? [ - (SignedMessageStatusesEnum.cancelled, SignedMessageStatusesEnum.failed) - ].includes(messageSession.status) && messageSession?.message - : false; - - const isSuccess = - messageSession?.message && - messageSession?.status === SignedMessageStatusesEnum.signed; - return (
- - - {(isSuccess || isError) && ( + {['success', 'error'].includes(state) ? ( + ) : ( + )}
- {!isSuccess && !isError && ( + {!['success', 'error'].includes(state) && (