diff --git a/.github/workflows/deploy-devnet.yml b/.github/workflows/deploy-devnet.yml index e1f6dfef..776aff71 100644 --- a/.github/workflows/deploy-devnet.yml +++ b/.github/workflows/deploy-devnet.yml @@ -18,7 +18,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '16.x' + node-version: '18.x' - name: Setup yarn run: npm install -g yarn - run: yarn install diff --git a/.github/workflows/deploy-integration.yml b/.github/workflows/deploy-integration.yml index 902477f3..8e868a32 100644 --- a/.github/workflows/deploy-integration.yml +++ b/.github/workflows/deploy-integration.yml @@ -18,7 +18,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '16.x' + node-version: '18.x' - name: Setup yarn run: npm install -g yarn - run: yarn install diff --git a/.github/workflows/deploy-mainnet.yml b/.github/workflows/deploy-mainnet.yml index 688c6f8f..6e0280a7 100644 --- a/.github/workflows/deploy-mainnet.yml +++ b/.github/workflows/deploy-mainnet.yml @@ -18,7 +18,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '16.x' + node-version: '18.x' - name: Setup yarn run: npm install -g yarn - run: yarn install diff --git a/.github/workflows/deploy-testnet.yml b/.github/workflows/deploy-testnet.yml index 986fd63b..18c48b56 100644 --- a/.github/workflows/deploy-testnet.yml +++ b/.github/workflows/deploy-testnet.yml @@ -18,7 +18,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '16.x' + node-version: '18.x' - name: Setup yarn run: npm install -g yarn - run: yarn install diff --git a/cypress/constants/enums.ts b/cypress/constants/enums.ts index 6d7ad424..8c5feb39 100644 --- a/cypress/constants/enums.ts +++ b/cypress/constants/enums.ts @@ -45,10 +45,3 @@ export const enum GlobalDataEnum { confirmedToast = 'transactions successful', cancelToast = 'Transaction canceled' } - -export const enum GlobalSelectorsEnum { - connect = 'Connect', - signAutoSend = 'sign-auto-send', - sendTransactions = 'send-transactions', - swapLock = 'swap-lock' -} diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 0f415237..59715fb9 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -23,7 +23,7 @@ Cypress.Commands.add('login', (walletID, selector) => { } cy.getSelector(GlobalSelectorsEnum.keystoreBtn).click(); cy.checkUrl(RoutesEnum.keystoreRoute); - cy.getSelector(GlobalSelectorsEnum.submitButton)).click(); + cy.getSelector(GlobalSelectorsEnum.submitButton).click(); cy.get('input[type=file]').selectFile('./cypress/assets/testKeystore.json', { force: true diff --git a/package.json b/package.json index d0b90231..9a70240e 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,13 @@ "license": "GPL-3.0-or-later", "repository": "@multiversx/mx-template-dapp", "dependencies": { - "@fortawesome/fontawesome-svg-core": "6.4.0", - "@fortawesome/free-solid-svg-icons": "6.4.0", + "@fortawesome/fontawesome-svg-core": "6.5.1", + "@fortawesome/free-solid-svg-icons": "6.5.1", "@fortawesome/react-fontawesome": "0.2.0", - "@multiversx/sdk-core": "12.16.0", - "@multiversx/sdk-dapp": "2.25.2", - "@multiversx/sdk-network-providers": "2.2.0", - "axios": "1.6.2", + "@multiversx/sdk-core": "13.0.0-beta.4", + "@multiversx/sdk-dapp": "2.29.0-beta.3", + "@multiversx/sdk-network-providers": "2.2.1", + "axios": "1.6.5", "classnames": "2.3.2", "moment": "2.29.4", "react": "18.2.0", diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index 6eb72c74..4a2daeb8 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -7,15 +7,17 @@ interface CardType extends PropsWithChildren, WithClassnameType { title: string; description?: string; reference: string; + anchor?: string; } export const Card = (props: CardType) => { - const { title, children, description, reference } = props; + const { title, children, description, reference, anchor } = props; return (

{title} diff --git a/src/config/sharedConfig.ts b/src/config/sharedConfig.ts index 678f8a94..081361a1 100644 --- a/src/config/sharedConfig.ts +++ b/src/config/sharedConfig.ts @@ -3,3 +3,21 @@ export const walletConnectV2ProjectId = '9b1a9564f91cb659ffe21b73d5c4e2d8'; export const apiTimeout = 6000; export const transactionSize = 10; export const nativeAuth = true; +export const BATCH_TRANSACTIONS_SC = { + egld_wEGLD: { + contract: 'erd1qqqqqqqqqqqqqpgqpv09kfzry5y4sj05udcngesat07umyj70n4sa2c0rp', + data: 'wrapEgld' + }, + wEGLD_USDC: { + contract: 'erd1qqqqqqqqqqqqqpgqtqfhy99su9xzjjrq59kpzpp25udtc9eq0n4sr90ax6', + data: 'ESDTTransfer@5745474C442D613238633539@06f05b59d3b20000@73776170546f6b656e734669786564496e707574@555344432D333530633465@01' + }, + wEGLD_MEX: { + contract: 'erd1qqqqqqqqqqqqqpgqzw0d0tj25qme9e4ukverjjjqle6xamay0n4s5r0v9g', + data: 'ESDTTransfer@5745474C442D613238633539@06f05b59d3b20000@73776170546f6b656e734669786564496e707574@4D45582D613635396430@01' + }, + lock_MEX: { + contract: 'erd1qqqqqqqqqqqqqpgq2l97gw2j4wnlem4y2rx7dudqlssjtwpu0n4sd0u3w2', + data: 'ESDTTransfer@4D45582D613635396430@0de0b6b3a7640000@6c6f636b546f6b656e73@05a0' + } +}; diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 1de9a200..e2e4ec74 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1,2 +1,3 @@ export * from './sdkDappHelpers'; export * from './pingPong'; +export * from './signAndSendTransactions'; diff --git a/src/helpers/sdkDappHelpers.ts b/src/helpers/sdkDappHelpers.ts index 26d2425a..9c56294c 100644 --- a/src/helpers/sdkDappHelpers.ts +++ b/src/helpers/sdkDappHelpers.ts @@ -4,3 +4,4 @@ export { refreshAccount } from '@multiversx/sdk-dapp/utils/account/refreshAccoun export { logout } from '@multiversx/sdk-dapp/utils/logout'; export { signTransactions } from '@multiversx/sdk-dapp/services/transactions/signTransactions'; export { trimUsernameDomain } from '@multiversx/sdk-dapp/hooks/account/helpers'; +export { newTransaction } from '@multiversx/sdk-dapp/models'; diff --git a/src/helpers/signAndSendTransactions.ts b/src/helpers/signAndSendTransactions.ts new file mode 100644 index 00000000..8ee8523a --- /dev/null +++ b/src/helpers/signAndSendTransactions.ts @@ -0,0 +1,26 @@ +import { Transaction, TransactionsDisplayInfoType } from 'types'; + +import { refreshAccount, sendTransactions } from './sdkDappHelpers'; + +type SignAndSendTransactionsProps = { + transactions: Transaction[]; + callbackRoute: string; + transactionsDisplayInfo: TransactionsDisplayInfoType; +}; + +export const signAndSendTransactions = async ({ + transactions, + callbackRoute, + transactionsDisplayInfo +}: SignAndSendTransactionsProps) => { + await refreshAccount(); + + const { sessionId } = await sendTransactions({ + transactions, + transactionsDisplayInfo, + redirectAfterSign: false, + callbackRoute + }); + + return sessionId; +}; diff --git a/src/hooks/index.ts b/src/hooks/index.ts index bb9f0607..f5eff249 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,3 +1,5 @@ export * from './sdkDappHooks'; export * from './withPageTitle'; export * from './transactions'; +export * from './useScrollToElement'; +export * from './useIsWebProvider'; diff --git a/src/hooks/sdkDappHooks.ts b/src/hooks/sdkDappHooks.ts index d1136ed8..4ed22c75 100644 --- a/src/hooks/sdkDappHooks.ts +++ b/src/hooks/sdkDappHooks.ts @@ -15,3 +15,4 @@ export { useCheckBatch } from '@multiversx/sdk-dapp/hooks/transactions/batch/tra export { useSignTransactions } from '@multiversx/sdk-dapp/hooks/transactions/useSignTransactions'; export { useBatchTransactionsTracker } from '@multiversx/sdk-dapp/hooks/transactions/batch/tracker/useBatchTransactionsTracker'; export { useGetSignedTransactions } from '@multiversx/sdk-dapp/hooks/transactions/useGetSignedTransactions'; +export { useGetAccountProvider } from '@multiversx/sdk-dapp/hooks/account/useGetAccountProvider'; diff --git a/src/hooks/transactions/useSendPingPongTransaction.ts b/src/hooks/transactions/useSendPingPongTransaction.ts index 0ddb3a33..e3615d23 100644 --- a/src/hooks/transactions/useSendPingPongTransaction.ts +++ b/src/hooks/transactions/useSendPingPongTransaction.ts @@ -1,18 +1,46 @@ -import { useState } from 'react'; +import { useState, useCallback } from 'react'; import { deleteTransactionToast, removeAllSignedTransactions, removeAllTransactionsToSign } from '@multiversx/sdk-dapp/services/transactions/clearTransactions'; import { contractAddress } from 'config'; -import { refreshAccount, sendTransactions } from 'helpers'; -import { useTrackTransactionStatus } from 'hooks/sdkDappHooks'; -import { SessionEnum } from 'localConstants'; -import { IPlainTransactionObject } from 'types/sdkCoreTypes'; +import { signAndSendTransactions } from 'helpers/signAndSendTransactions'; +import { + useGetAccountInfo, + useGetNetworkConfig, + useTrackTransactionStatus +} from 'hooks/sdkDappHooks'; +import { GAS_PRICE, SessionEnum, VERSION } from 'localConstants'; import { getChainId } from 'utils/getChainId'; import { smartContract } from 'utils/smartContract'; +import { + PingRawProps, + PingPongServiceProps, + PongRawProps +} from 'types/pingPong.types'; +import { newTransaction } from 'helpers/sdkDappHelpers'; +import { Address } from 'utils/sdkDappCore'; + +type PingPongTransactionProps = { + type: SessionEnum; +}; + +const PING_TRANSACTION_INFO = { + processingMessage: 'Processing Ping transaction', + errorMessage: 'An error has occured during Ping', + successMessage: 'Ping transaction successful' +}; + +const PONG_TRANSACTION_INFO = { + processingMessage: 'Processing Pong transaction', + errorMessage: 'An error has occured during Pong', + successMessage: 'Pong transaction successful' +}; -export const useSendPingPongTransaction = (type: SessionEnum) => { +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 @@ -20,6 +48,9 @@ export const useSendPingPongTransaction = (type: SessionEnum) => { sessionStorage.getItem(type) ); + const network = useGetNetworkConfig(); + const { address, account } = useGetAccountInfo(); + const transactionStatus = useTrackTransactionStatus({ transactionId: pingPongSessionId ?? '0' }); @@ -30,147 +61,141 @@ export const useSendPingPongTransaction = (type: SessionEnum) => { deleteTransactionToast(pingPongSessionId ?? ''); }; - const sendPingTransaction = async (amount?: string) => { - clearAllTransactions(); - - const pingTransaction = { - value: amount, - data: 'ping', - receiver: contractAddress, - gasLimit: '60000000' - }; - - await refreshAccount(); - const { sessionId } = await sendTransactions({ - transactions: pingTransaction, - transactionsDisplayInfo: { - processingMessage: 'Processing Ping transaction', - errorMessage: 'An error has occured during Ping', - successMessage: 'Ping transaction successful' - }, - redirectAfterSign: false - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }; + 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 sendPingTransactionFromAbi = async (amount?: string) => { - clearAllTransactions(); - - const pingTransaction = smartContract.methodsExplicit - .ping() - .withValue(amount ?? '0') - .withGasLimit(60000000) - .withChainID(getChainId()) - .buildTransaction() - .toPlainObject(); - - await refreshAccount(); - const { sessionId } = await sendTransactions({ - transactions: pingTransaction, - transactionsDisplayInfo: { - processingMessage: 'Processing Ping transaction', - errorMessage: 'An error has occured during Ping', - successMessage: 'Ping transaction successful' - }, - redirectAfterSign: false - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }; + const sendPingTransactionFromAbi = useCallback( + async ({ amount, callbackRoute }: PingRawProps) => { + clearAllTransactions(); + + const pingTransaction = smartContract.methodsExplicit + .ping() + .withSender(new Address(address)) + .withValue(amount ?? '0') + .withGasLimit(60000000) + .withChainID(getChainId()) + .buildTransaction(); + + const sessionId = await signAndSendTransactions({ + transactions: [pingTransaction], + callbackRoute, + transactionsDisplayInfo: PING_TRANSACTION_INFO + }); + + sessionStorage.setItem(type, sessionId); + setPingPongSessionId(sessionId); + }, + [] + ); - const sendPingTransactionFromService = async ( - transaction: IPlainTransactionObject - ) => { - clearAllTransactions(); - - await refreshAccount(); - const { sessionId } = await sendTransactions({ - transactions: [transaction], - transactionsDisplayInfo: { - processingMessage: 'Processing Ping transaction', - errorMessage: 'An error has occured during Ping', - successMessage: 'Ping transaction successful' - }, - redirectAfterSign: false - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }; + const sendPingTransactionFromService = useCallback( + async ({ transactions, callbackRoute }: PingPongServiceProps) => { + clearAllTransactions(); - const sendPongTransaction = async () => { - clearAllTransactions(); - - const pongTransaction = { - value: '0', - data: 'pong', - receiver: contractAddress, - gasLimit: '60000000' - }; - - await refreshAccount(); - const { sessionId } = await sendTransactions({ - transactions: pongTransaction, - transactionsDisplayInfo: { - processingMessage: 'Processing Pong transaction', - errorMessage: 'An error has occured during Pong', - successMessage: 'Pong transaction successful' - }, - redirectAfterSign: false - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }; + const sessionId = await signAndSendTransactions({ + transactions, + callbackRoute, + transactionsDisplayInfo: PING_TRANSACTION_INFO + }); - const sendPongTransactionFromAbi = async () => { - clearAllTransactions(); - - const pongTransaction = smartContract.methodsExplicit - .pong() - .withValue('0') - .withGasLimit(60000000) - .withChainID(getChainId()) - .buildTransaction() - .toPlainObject(); - - await refreshAccount(); - const { sessionId } = await sendTransactions({ - transactions: pongTransaction, - transactionsDisplayInfo: { - processingMessage: 'Processing Pong transaction', - errorMessage: 'An error has occured during Pong', - successMessage: 'Pong transaction successful' - }, - redirectAfterSign: false - }); - - sessionStorage.setItem(type, sessionId); - setPingPongSessionId(sessionId); - }; + sessionStorage.setItem(type, sessionId); + setPingPongSessionId(sessionId); + }, + [] + ); - const sendPongTransactionFromService = async ( - transaction: IPlainTransactionObject - ) => { - clearAllTransactions(); - - await refreshAccount(); - const { sessionId } = await sendTransactions({ - transactions: [transaction], - transactionsDisplayInfo: { - processingMessage: 'Processing Pong transaction', - errorMessage: 'An error has occured during Pong', - successMessage: 'Pong transaction successful' - }, - redirectAfterSign: false - }); - - 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 pongTransaction = smartContract.methodsExplicit + .pong() + .withSender(new Address(address)) + .withValue('0') + .withGasLimit(60000000) + .withChainID(getChainId()) + .buildTransaction(); + + 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); + }, + [] + ); return { sendPingTransaction, diff --git a/src/hooks/useIsWebProvider.ts b/src/hooks/useIsWebProvider.ts new file mode 100644 index 00000000..0828fa05 --- /dev/null +++ b/src/hooks/useIsWebProvider.ts @@ -0,0 +1,9 @@ +import { LoginMethodsEnum } from 'types/sdkDappTypes'; +import { useGetAccountProvider } from './sdkDappHooks'; + +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 new file mode 100644 index 00000000..62489666 --- /dev/null +++ b/src/hooks/useScrollToElement.ts @@ -0,0 +1,22 @@ +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/localConstants/sdkDapConstants.ts b/src/localConstants/sdkDapConstants.ts index 5ae9fe3b..2faa2672 100644 --- a/src/localConstants/sdkDapConstants.ts +++ b/src/localConstants/sdkDapConstants.ts @@ -1 +1,7 @@ -export { DECIMALS, GAS_PRICE, GAS_LIMIT } from '@multiversx/sdk-dapp/constants'; +export { + DECIMALS, + GAS_PRICE, + GAS_LIMIT, + EXTRA_GAS_LIMIT_GUARDED_TX, + VERSION +} from '@multiversx/sdk-dapp/constants'; diff --git a/src/pages/Dashboard/Dashboard.tsx b/src/pages/Dashboard/Dashboard.tsx index b6e8afec..8a3f90a7 100644 --- a/src/pages/Dashboard/Dashboard.tsx +++ b/src/pages/Dashboard/Dashboard.tsx @@ -1,4 +1,3 @@ -import { Card } from 'components/Card'; import { contractAddress } from 'config'; import { AuthRedirectWrapper } from 'wrappers'; import { @@ -11,16 +10,11 @@ import { PingPongService, Transactions } from './widgets'; +import { useScrollToElement } from 'hooks'; +import { Widget } from './components'; +import { WidgetType } from 'types/widget.types'; -type WidgetsType = { - title: string; - widget: (props: any) => JSX.Element; - description?: string; - props?: { receiver?: string }; - reference: string; -}; - -const WIDGETS: WidgetsType[] = [ +const WIDGETS: WidgetType[] = [ { title: 'Account', widget: Account, @@ -33,7 +27,8 @@ const WIDGETS: WidgetsType[] = [ description: 'Smart Contract interactions using manually formulated transactions', reference: - 'https://docs.multiversx.com/sdk-and-tools/indices/es-index-transactions/' + 'https://docs.multiversx.com/sdk-and-tools/indices/es-index-transactions/', + anchor: 'ping-pong-manual' }, { title: 'Ping & Pong (ABI)', @@ -41,20 +36,23 @@ const WIDGETS: WidgetsType[] = [ 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' + 'https://docs.multiversx.com/sdk-and-tools/sdk-js/sdk-js-cookbook/#using-interaction-when-the-abi-is-available', + anchor: 'ping-pong-abi' }, { title: 'Ping & Pong (Backend)', widget: PingPongService, description: 'Smart Contract interactions using the backend generated transactions', - reference: 'https://github.com/multiversx/mx-ping-pong-service' + reference: 'https://github.com/multiversx/mx-ping-pong-service', + anchor: 'ping-pong-backend' }, { title: 'Sign message', widget: SignMessage, description: 'Message signing using the connected account', - reference: 'https://docs.multiversx.com/sdk-and-tools/sdk-dapp/#account-1' + reference: 'https://docs.multiversx.com/sdk-and-tools/sdk-dapp/#account-1', + anchor: 'sign-message' }, { title: 'Native auth', @@ -69,7 +67,8 @@ const WIDGETS: WidgetsType[] = [ 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' + 'https://github.com/multiversx/mx-sdk-dapp#sending-transactions-synchronously-in-batches', + anchor: 'batch-transactions' }, { title: 'Transactions (All)', @@ -88,29 +87,16 @@ const WIDGETS: WidgetsType[] = [ } ]; -export const Dashboard = () => ( - -
- {WIDGETS.map((element) => { - const { - title, - widget: MxWidget, - description, - props = {}, - reference - } = element; +export const Dashboard = () => { + useScrollToElement(); - return ( - - - - ); - })} -
-
-); + return ( + +
+ {WIDGETS.map((element) => ( + + ))} +
+
+ ); +}; diff --git a/src/pages/Dashboard/components/Widget.tsx b/src/pages/Dashboard/components/Widget.tsx new file mode 100644 index 00000000..ec796eb1 --- /dev/null +++ b/src/pages/Dashboard/components/Widget.tsx @@ -0,0 +1,29 @@ +import { Card } from 'components/Card'; +import { getCallbackRoute } from 'utils/getCallbackRoute'; +import { WidgetType } from 'types/widget.types'; +import { useIsWebProvider } from 'hooks'; + +export const Widget = ({ + title, + description, + reference, + anchor, + widget: MxWidget, + props = {} +}: WidgetType) => { + const { isWebProvider } = useIsWebProvider(); + const callbackRoute = anchor + ? getCallbackRoute({ anchor, isWebProvider }) + : ''; + + return ( + + + + ); +}; diff --git a/src/pages/Dashboard/components/index.ts b/src/pages/Dashboard/components/index.ts new file mode 100644 index 00000000..b42adc88 --- /dev/null +++ b/src/pages/Dashboard/components/index.ts @@ -0,0 +1 @@ +export * from './Widget'; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx b/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx index 40cc8940..d1b9dfdd 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx +++ b/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx @@ -5,24 +5,30 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useGetBatches } from '@multiversx/sdk-dapp/hooks/transactions/batch/useGetBatches'; -import { sendBatchTransactions } from '@multiversx/sdk-dapp/services/transactions/sendBatchTransactions'; import { Button } from 'components/Button'; import { OutputContainer, TransactionsOutput } from 'components/OutputContainer'; -import { sendTransactions } from 'helpers'; -import { useGetAccountInfo, useGetPendingTransactions } from 'hooks'; -import { SessionEnum } from 'localConstants'; -import { SignedTransactionType } from 'types'; +import { + useGetAccountInfo, + useGetNetworkConfig, + useGetPendingTransactions +} from 'hooks'; +import { SessionEnum } from 'localConstants/session'; +import { SignedTransactionType, WidgetProps } from 'types'; import { useBatchTransactionContext } from 'wrappers'; -import { getBatchTransactions, getSwapAndLockTransactions } from './helpers'; import { useSendSignedTransactions } from './hooks'; -import { BatchTransactionsType } from './types'; +import { + sendBatchTransactions, + signAndAutoSendBatchTransactions, + swapAndLockTokens +} from './helpers'; -export const BatchTransactions = () => { +export const BatchTransactions = ({ callbackRoute }: WidgetProps) => { const { setSendBatchTransactionsOnDemand } = useBatchTransactionContext(); - const { address } = useGetAccountInfo(); + const { address, account } = useGetAccountInfo(); + const network = useGetNetworkConfig(); const { batches } = useGetBatches(); const { hasPendingTransactions } = useGetPendingTransactions(); const [trackBatchId, setTrackBatchId] = useState( @@ -32,109 +38,83 @@ export const BatchTransactions = () => { const [stateTransactions, setStateTransactions] = useState< SignedTransactionType[] | null >(null); - const [transactionsOrder, setTransactionsOrder] = useState([]); const [currentSessionId, setCurrentSessionId] = useState( sessionStorage.getItem(SessionEnum.signedSessionId) ); const { batchId, setBatchSessionId } = useSendSignedTransactions({ - signedSessionId: currentSessionId, - transactionsOrder + signedSessionId: currentSessionId }); - // this process will not go through useSendSignedTransactions - // it will automatically sign and send transactions - const signAndAutoSendBatchTransactions = async () => { + // 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 executeSignAndAutoSendBatchTransactions = async () => { setSendBatchTransactionsOnDemand(false); - const payload = getBatchTransactions(address); - const { transactions } = payload; - - const groupedTransactions = [ - [transactions[0]], - [transactions[1], transactions[2]], - [transactions[3], transactions[4]] - ]; - - const { batchId: currentBatchId, error } = await sendBatchTransactions({ - transactions: groupedTransactions, - callbackRoute: window.location.pathname, - customTransactionInformation: { redirectAfterSign: true }, - transactionsDisplayInfo: { - processingMessage: 'Processing transactions', - errorMessage: 'An error has occurred during transaction execution', - successMessage: 'Batch transactions successful' - } + const { batchId } = await signAndAutoSendBatchTransactions({ + address, + nonce: account.nonce, + chainID: network.chainID, + callbackRoute }); - if (error) { - console.error('Could not execute transactions', error); + if (!batchId) { return; } - sessionStorage.setItem(SessionEnum.batchId, currentBatchId); - setTrackBatchId(currentBatchId); - }; - - const executeBatchTransactions = () => { - const payload = getBatchTransactions(address); - executeTransactions(payload); - }; - - const executeSwapAndLockTransactions = () => { - const payload = getSwapAndLockTransactions(address); - executeTransactions(payload); + setTrackBatchId(batchId); }; - const executeTransactions = async (payload: BatchTransactionsType) => { + const executeBatchTransactions = async () => { setSendBatchTransactionsOnDemand(true); - const { transactions, order } = payload; - - const { sessionId, error } = await sendTransactions({ - transactions, - signWithoutSending: true, - callbackRoute: window.location.pathname, - customTransactionInformation: { redirectAfterSign: true } + const { newBatchSessionId, sessionId } = await sendBatchTransactions({ + address, + nonce: account.nonce, + chainID: network.chainID, + callbackRoute }); - if (error) { - console.error('Could not execute transactions', error); + if (!newBatchSessionId || !sessionId) { return; } - if (order) { - setTransactionsOrder(order); - } - - 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); - setBatchSessionId(newBatchSessionId); setCurrentSessionId(sessionId); }; - // If manual batch transactions are executed, track the batchId - useEffect(() => { - if (batchId) { - setTrackBatchId(batchId); - } - }, [batchId]); + const executeSwapAndLockTokens = async () => { + setSendBatchTransactionsOnDemand(true); + const { batchId: currentBatchId } = await swapAndLockTokens({ + address, + nonce: account.nonce, + chainID: network.chainID, + callbackRoute + }); - useEffect(() => { - if (trackBatchId && batches[trackBatchId]) { - setStateTransactions(batches[trackBatchId].transactions.flat()); + if (!currentBatchId) { + return; } - }, [trackBatchId, batches]); + + setTrackBatchId(currentBatchId); + }; return (