{"id":13407847,"url":"https://github.com/multiversx/mx-sdk-dapp","last_synced_at":"2026-01-22T12:45:03.083Z","repository":{"id":36964875,"uuid":"432991695","full_name":"multiversx/mx-sdk-dapp","owner":"multiversx","description":"A library that holds the core functional logic of a dapp on the MultiversX","archived":false,"fork":false,"pushed_at":"2026-01-20T11:51:17.000Z","size":43138,"stargazers_count":82,"open_issues_count":1,"forks_count":79,"subscribers_count":20,"default_branch":"main","last_synced_at":"2026-01-20T20:39:03.834Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/multiversx.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-11-29T10:07:40.000Z","updated_at":"2026-01-19T13:52:34.000Z","dependencies_parsed_at":"2025-11-22T10:07:07.650Z","dependency_job_id":null,"html_url":"https://github.com/multiversx/mx-sdk-dapp","commit_stats":{"total_commits":2606,"total_committers":36,"mean_commits":72.38888888888889,"dds":0.7843438219493477,"last_synced_commit":"ac91a916f43199d5e03d4eddd14c2e6eac3f837d"},"previous_names":["elrondnetwork/dapp-core"],"tags_count":277,"template":false,"template_full_name":null,"purl":"pkg:github/multiversx/mx-sdk-dapp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiversx%2Fmx-sdk-dapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiversx%2Fmx-sdk-dapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiversx%2Fmx-sdk-dapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiversx%2Fmx-sdk-dapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/multiversx","download_url":"https://codeload.github.com/multiversx/mx-sdk-dapp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiversx%2Fmx-sdk-dapp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28663127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:00:48.991Z","updated_at":"2026-01-22T12:45:03.077Z","avatar_url":"https://github.com/multiversx.png","language":"TypeScript","readme":"# MultiversX SDK for Front-End DApps\n\n[![Unit tests](https://github.com/multiversx/mx-sdk-dapp/actions/workflows/pre-merge-unit-tests.yml/badge.svg)](https://github.com/multiversx/mx-sdk-dapp/actions/workflows/pre-merge-unit-tests.yml)\n[![Coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/multiversx/mx-sdk-dapp/main/coverage-total.json\u0026logo=github\u0026logoColor=white)](https://raw.githubusercontent.com/multiversx/mx-sdk-dapp/main/coverage-total.json)\n[![Integration tests](https://github.com/multiversx/mx-sdk-dapp/actions/workflows/run-template-dapps-integration.yml/badge.svg)](https://github.com/multiversx/mx-sdk-dapp/actions/workflows/run-template-dapps-integration.yml)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/multiversx/mx-sdk-dapp)\n\nMultiversX Front-End SDK for JavaScript and TypeScript (written in TypeScript).\n\n## Introduction\n\n`sdk-dapp` is a library that holds core functional logic that can be used to create a dApp on MultiversX Network.\n\nIt is built for applications that use any of the following technologies:\n\n- React (example: [React Template Dapp](https://github.com/multiversx/mx-template-dapp))\n- React JS (example: [React JS Template Dapp](https://github.com/multiversx/mx-template-dapp-reactjs))\n- Angular (example: [Angular Template Dapp](https://github.com/multiversx/mx-template-dapp-angular))\n- Vue (example: [Vue Template Dapp](https://github.com/multiversx/mx-template-dapp-vue))\n- Any other JavaScript framework (e.g. Solid.js etc.) (example: [Solid.js Dapp](https://github.com/multiversx/mx-solidjs-template-dapp))\n- React Native (example: [React Native Dapp](https://github.com/multiversx/mx-template-dapp-react-native))\n- Next.js (example: [Next.js Dapp](https://github.com/multiversx/mx-template-dapp-nextjs))\n\n## GitHub project\n\nThe GitHub repository can be found here: [https://github.com/multiversx/mx-sdk-dapp](https://github.com/multiversx/mx-sdk-dapp)\n\n## Live demo: template-dapp\n\nSee [Template dApp](https://template-dapp.multiversx.com/) for live demo or check out usage in the [Github repo](https://github.com/multiversx/mx-template-dapp)\n\n## Requirements\n\n- Node.js version 20.13.1+\n- Npm version 10.5.2+\n\n## Distribution\n\n[npm](https://www.npmjs.com/package/@multiversx/sdk-dapp)\n\n## Installation\n\nThe library can be installed via npm or yarn.\n\n```bash\nnpm install @multiversx/sdk-dapp\n```\n\nor\n\n```bash\nyarn add @multiversx/sdk-dapp\n```\n\n\u003e **Note:** Make sure you run your app on `https`, not `http`, otherwise some providers will not work.\n\nIf you're transitioning from `@multiversx/sdk-dapp@4.x`, you can check out the [Migration guide](https://github.com/multiversx/mx-template-dapp/blob/main/MIGRATION_GUIDE.md) and the [migration PR](https://github.com/multiversx/mx-template-dapp/pull/343) of Template Dapp\n\n## Usage\n\nsdk-dapp aims to abstract and simplify the process of interacting with users' wallets and with the MultiversX blockchain, allowing developers to easily get started with new applications.\n\n```mermaid\nflowchart LR\n    A[\"Signing Providers \u0026 APIs\"] \u003c--\u003e B[\"sdk-dapp\"] \u003c--\u003e C[\"dApp\"]\n```\n\nThe basic concepts you need to understand are configuration, provider interaction, transactions, and presenting data. These are the building blocks of any dApp, and they are abstracted in the `sdk-dapp` library.\n\nHaving this knowledge, we can consider several steps needed to put a dApp together:\n\n**Table 1**. Steps to build a dApp\n| # | Step | Description |\n|---|------|-------------|\n| 1 | Configuration | - storage configuration (e.g. sessionStorage, localStorage etc.)\u003cbr\u003e- chain configuration\u003cbr\u003e- custom provider configuration (adding / disabling / changing providers) |\n| 2 | Provider interaction | - logging in and out\u003cbr\u003e- signing transactions / messages |\n| 3 | Presenting data | - get store data (e.g. account balance, account address etc.)\u003cbr\u003e- use components to display data (e.g. balance, address, transactions list) |\n| 4 | Transactions | - sending transactions\u003cbr\u003e- tracking transactions\u003cbr\u003e- displaying transactions history |\n\nEach of these steps will be explained in more detail in the following sections.\n\n### 1. Configuration\n\nBefore your application bootstraps, you need to configure the storage, the network, and the signing providers. This is done by calling the `initApp` method from the `methods` folder. It is recommended to call this method in the `index.tsx` to ensure the sdk-dapp internal functions are initialized before rendering the app.\n\n```typescript\n// index.tsx\nimport { initApp } from '@multiversx/sdk-dapp/out/methods/initApp/initApp';\nimport type { InitAppType } from '@multiversx/sdk-dapp/out/methods/initApp/initApp.types';\nimport { EnvironmentsEnum } from '@multiversx/sdk-dapp/out/types/enums.types';\nimport { App } from \"./App\";\n\nconst config: InitAppType = {\n  storage: { getStorageCallback: () =\u003e sessionStorage },\n  dAppConfig: {\n    // nativeAuth: true, // optional\n    environment: EnvironmentsEnum.devnet,\n    // network: { // optional\n    //   walletAddress: 'https://devnet-wallet.multiversx.com' // or other props you want to override\n    // },\n    // transactionTracking: { // optional\n    //   successfulToastLifetime: 5000,\n    //   onSuccess: async (sessionId) =\u003e {\n    //     console.log('Transaction session successful', sessionId);\n    //   },\n    //   onFail: async (sessionId) =\u003e {\n    //     console.log('Transaction session failed', sessionId);\n    // }\n  }\n  // customProviders: [myCustomProvider] // optional\n};\n\ninitApp(config).then(() =\u003e {\n  render(() =\u003e \u003cApp /\u003e, root!); // render your app\n});\n```\n\n### 2. Provider interaction\n\nOnce your dApp has loaded, the first user action is logging in with a chosen provider. There are two ways to perform a login: using the `UnlockPanelManager` and programmatic login using the `ProviderFactory`.\n\n#### 2.1 Using the `UnlockPanelManager`\n\nBy using the provided UI, you get the benefit of having all supported providers ready for login in a side panel. You simply need to link the `unlockPanelManager.openUnlockPanel` to a user action.\n\n```typescript\nimport { UnlockPanelManager } from '@multiversx/sdk-dapp/out/managers/UnlockPanelManager';\nimport { ProviderFactory } from '@multiversx/sdk-dapp/out/providers/ProviderFactory';\n\nexport const ConnectButton = () =\u003e {\n  const unlockPanelManager = UnlockPanelManager.init({\n    loginHandler: () =\u003e {\n      navigate('/dashboard');\n    },\n    onClose: () =\u003e { // optional action to be performed when the user closes the Unlock Panel\n      navigate('/');\n    },\n    // allowedProviders: [ProviderTypeEnum.walletConnect, 'myCustomProvider'] // optionally, only show specific providers\n  });\n  const handleOpenUnlockPanel = () =\u003e {\n    unlockPanelManager.openUnlockPanel();\n  };\n  return \u003cButton onClick={handleOpenUnlockPanel}\u003eConnect\u003c/Button\u003e;\n};\n\n```\n\nOnce the user has logged in, if `nativeAuth` is configured in the `initApp` method, an automatic logout will be performed upon native auth expiration. Before the actual logout is performed, the `LogoutManager` will show a warning toast to the user. This toast can be customized by passing a `tokenExpirationToastWarningSeconds` to the `nativeAuth` config.\n\n```typescript\n// in initApp config\nconst config: InitAppType = {\n  // ...\n  nativeAuth: {\n    expirySeconds: 30, // test auto logout after 30 seconds\n    tokenExpirationToastWarningSeconds: 10 // show warning toast 10 seconds before auto logout\n  }\n};\n```\n\nYou have the option to stop this behavior by calling `LogoutManager.getInstance().stop()` after the user has logged in.\n\n```typescript\nimport { LogoutManager } from '@multiversx/sdk-dapp/out/managers/LogoutManager/LogoutManager';\n\n  loginHandler: () =\u003e {\n    navigate('/dashboard');\n    // optional, to stop the automatic logout upon native auth expiration\n    LogoutManager.getInstance().stop();\n  },\n```\n\nIf you want to perform some actions as soon as the user has logged in, you will need to call `ProviderFactory.create` inside a handler accepting arguments.\n\n```typescript\nexport const AdvancedConnectButton = () =\u003e {\n  const unlockPanelManager = UnlockPanelManager.init({\n    loginHandler: async ({ type, anchor }) =\u003e {\n      const provider = await ProviderFactory.create({\n        type,\n        anchor\n      });\n      const { address, signature } = await provider.login();\n      navigate(`/dashboard?address=${address}`);\n    },\n    onCancelLogin: async () =\u003e { // optional action to be performed when the user cancels the login\n      navigate('/');\n    }\n  });\n  const handleOpenUnlockPanel = () =\u003e {\n    unlockPanelManager.openUnlockPanel();\n    // if you want to select a specific provider for your user, you can call\n    // unlockPanelManager.selectProvider(ProviderTypeEnum.extension);\n  };\n  return \u003cButton onClick={handleOpenUnlockPanel}\u003eAdvanced Connect\u003c/Button\u003e;\n};\n\n```\n\n#### 2.2 Programmatic login using the `ProviderFactory`\n\nIf you want to login using your custom UI, you can link user actions to specific providers by calling the `ProviderFactory`.\n\n```typescript\nimport { ProviderTypeEnum } from '@multiversx/sdk-dapp/out/providers/types/providerFactory.types';\n\nconst provider = await ProviderFactory.create({\n  type: ProviderTypeEnum.extension\n});\nawait provider.login();\n```\n\n\u003e **Note:** Extension and Ledger login will only work if dApp is served over HTTPS protocol\n\n### 3. Displaying app data\n\nDepending on the framework, you can either use hooks or selectors to get the user details:\n\n#### 3.1 React hooks\n\nIf you are using React, all hooks can be found under the `/out/react` folder. All store information can be accessed via different hooks, but below you will find the main hooks related to the most common use cases\n\n```bash\nout/react/\n├── account/useGetAccount ### access account data like address, balance and nonce\n├── loginInfo/useGetLoginInfo ### access login data like accessToken and provider type\n├── network/useGetNetworkConfig ### access network information like chainId and egldLabel\n├── store/useSelector ### make use of the useSelector hook for querying the store via selectors\n└── transactions/useGetTransactionSessions ### access all current and historic transaction sessions\n```\n\nBelow is an example of using the hooks to display the user address and balance.\n\n```typescript\nimport { useGetAccount } from '@multiversx/sdk-dapp/out/react/account/useGetAccount';\nimport { useGetNetworkConfig } from '@multiversx/sdk-dapp/out/react/network/useGetNetworkConfig';\n\nconst account = useGetAccount();\nconst {\n  network: { egldLabel }\n} = useGetNetworkConfig();\n\nconsole.log(account.address);\nconsole.log(`${account.balance} ${egldLabel}`);\n```\n\n#### 3.2 Store selector functions:\n\nIf you are not using the React ecosystem, you can use store selectors to get the store data, but note that information will not be reactive unless you subscribe to store changes.\n\n```typescript\nimport { getAccount } from '@multiversx/sdk-dapp/out/methods/account/getAccount';\nimport { getNetworkConfig } from '@multiversx/sdk-dapp/out/methods/network/getNetworkConfig';\n\nconst account = getAccount();\nconst { egldLabel } = getNetworkConfig();\n```\n\nIn order to get live updates you may need to subscribe to the store like this:\n\n```typescript\nimport { createSignal, onCleanup } from 'solid-js';\nimport { getStore } from '@multiversx/sdk-dapp/out/store/store';\n\nexport function useStore() {\n  const store = getStore();\n  const [state, setState] = createSignal(store.getState());\n\n  const unsubscribe = store.subscribe((newState) =\u003e {\n    setState(newState);\n  });\n\n  onCleanup(() =\u003e unsubscribe());\n\n  return state;\n}\n```\n\n### 4. Transactions\n\n#### 4.1 Signing transactions\n\nTo sign transactions, you first need to create the `Transaction` object, then pass it to the initialized provider.\n\n```typescript\nimport { Address, Transaction } from '@multiversx/sdk-core';\nimport {\n  GAS_PRICE,\n  GAS_LIMIT\n} from '@multiversx/sdk-dapp/out/constants/mvx.constants';\nimport { getAccountProvider } from '@multiversx/sdk-dapp/out/providers/helpers/accountProvider';\nimport { refreshAccount } from '@multiversx/sdk-dapp/out/utils/account/refreshAccount';\n\nconst pongTransaction = new Transaction({\n  value: BigInt(0),\n  data: Buffer.from('pong'),\n  receiver: Address.newFromBech32(contractAddress),\n  gasLimit: BigInt(GAS_LIMIT),\n  gasPrice: BigInt(GAS_PRICE),\n  chainID: network.chainId,\n  nonce: BigInt(account.nonce),\n  sender: Address.newFromBech32(account.address),\n  version: 1\n});\n\nawait refreshAccount(); // optionally, to get the latest nonce\nconst provider = getAccountProvider();\nconst signedTransactions = await provider.signTransactions(transactions);\n```\n\n#### 4.1.1 Signing Options\n\nThe `signTransactions` method accepts an optional second parameter with signing options:\n\n```typescript\nimport type { SignTransactionsOptionsType } from '@multiversx/sdk-dapp/out/providers/DappProvider/helpers/signTransactions/signTransactionsWithProvider';\n\nconst options: SignTransactionsOptionsType = {\n  skipGuardian?: boolean;  // Skip guardian validation for guarded accounts\n  callback?: (signedTransactions: Transaction[]) =\u003e Promise\u003cTransaction[]\u003e; // Post-signing callback\n};\n\nconst signedTransactions = await provider.signTransactions(transactions, options);\n```\n\n**Available options:**\n\n- `skipGuardian` (`boolean`): Optional. When `true`, skips the guardian co-signing step for guarded accounts. Useful for transactions that don't require guardian approval.\n\n- `callback` (`(signedTransactions: Transaction[]) =\u003e Promise\u003cTransaction[]\u003e`): Optional. A callback function that receives the signed transactions after all transactions have been signed by the user, but before guardian validation. This allows you to modify, filter, or perform additional processing on the signed transactions. The returned transactions will proceed to guardian validation (if applicable).\n\n**Example: Using the callback option**\n\nThe `callback` option is particularly useful for:\n\n- **Guarded accounts**: Processing signed transactions before they are sent to the guardian service for co-signing\n- **Custom validation**: Adding additional validation logic after user signing\n- **Logging/Analytics**: Recording signed transactions before final submission\n\n```typescript\nconst signedTransactions = await provider.signTransactions(transactions, {\n  callback: async (signedTxs) =\u003e {\n    // Example: Log signed transactions before guardian processing\n    console.log('User signed transactions:', signedTxs);\n\n    // Return the transactions to proceed with guardian validation\n    return signedTxs;\n  }\n});\n```\n\n#### 4.2 Sending and tracking transactions\n\nThen, to send the transactions, you need to use the `TransactionManager` class and pass in the `signedTransactions` to the `send` method. You can then track the transactions by using the `track` method. This will create a toast notification with the transaction hash and its status.\n\n\u003e **Note:** You can set callbacks for the transaction manager to handle the session status, by using the `setCallbacks` method on the `TransactionManager` class. This can also be configured globally in the `initApp` method.\n\n```typescript\nimport { TransactionManager } from '@multiversx/sdk-dapp/out/managers/TransactionManager';\nimport type { TransactionsDisplayInfoType } from '@multiversx/sdk-dapp/out/types/transactions.types';\n\nconst txManager = TransactionManager.getInstance();\n\nconst sentTransactions = await txManager.send(signedTransactions);\n\nconst toastInformation: TransactionsDisplayInfoType = {\n  processingMessage: 'Processing transactions',\n  errorMessage: 'An error has occurred during transaction execution',\n  successMessage: 'Transactions executed'\n};\n\nconst sessionId = await txManager.track(sentTransactions, {\n  transactionsDisplayInfo: toastInformation\n});\n```\n\n#### 4.3 Using the Notifications Feed\n\nThe Notifications Feed is a component that displays **session transactions** in a list. Internally it gets initialized in the `initApp` method. It can be accessed via the `NotificationManager.getInstance()` method.\nOnce the user logs out of the dApp, all transactions displayed by the Notifications Feed are removed from the store. Note that you can switch between toast notifications and Notifications Feed by pressing the View All button above the current pending transaction toast in the UI.\n\n```typescript\nconst notificationManager = NotificationManager.getInstance();\nawait notificationManager.openNotificationsFeed();\n```\n\n#### 4.4 Inspecting transactions\n\nYou can find both methods and hooks to access transactions data, as seen in the table below.\n\n**Table 2**. Inspecting transactions\n| # | Helper | Description | React hook equivalent |\n|---|------|-------------|----|\n| | `methods/transactions` | path | `react/transactions` |\n| 1 | `getTransactionSessions()` | returns all transaction sessions |`useGetTransactionSessions()` |\n| 2 | `getPendingTransactionsSessions()` | returns a record of pending sessions | `useGetPendingTransactionsSessions()`|\n| 3 | `getPendingTransactions()` | returns an array of signed transactions | `useGetPendingTransactions()` |\n| 4 | `getFailedTransactionsSessions()` | returns a record of failed sessions | `useGetFailedTransactionsSessions()`|\n| 5 | `getFailedTransactions()` | returns an array of failed transactions | `useGetFailedTransactions()`|\n| 6 | `getSuccessfulTransactionsSessions()` | returns a record of successful sessions | `useGetSuccessfulTransactionsSessions()`|\n| 7 | `getSuccessfulTransactions()` | returns an array of successful transactions | `useGetSuccessfulTransactions()`|\n\nThere is a way to inspect store information regarding a specific transaction, using the `transactionsSliceSelector`. An example is shown below:\n\n```typescript\nimport {\n  pendingTransactionsSessionsSelector,\n  transactionsSliceSelector\n} from '@multiversx/sdk-dapp/out/store/selectors/transactionsSelector';\nimport { getStore } from '@multiversx/sdk-dapp/out/store/store';\n\nconst store = getStore(); // or use useStore hook for reactivity\nconst pendingSessions = pendingTransactionsSessionsSelector(store.getState());\nconst allTransactionSessions = transactionsSliceSelector(store.getState());\n\nconst isSessionIdPending = Object.keys(pendingSessions).includes(sessionId);\nconst currentSession = allTransactionSessions[sessionId];\nconst currentSessionStatus = currentSession?.status;\nconst currentTransaction = currentSession?.transactions?.[0];\nconst currentTransactionStatus = currentTransaction?.status;\n```\n\n#### 4.5 Logging out\n\nThe user journey ends with calling the `provider.logout()` method.\n\n```typescript\nimport { getAccountProvider } from '@multiversx/sdk-dapp/out/providers/helpers/accountProvider';\nconst provider = getAccountProvider();\nawait provider.logout();\n```\n\n## Internal structure\n\nWe have seen in the previous chapter what are the minimal steps to get up and running with a blockchain interaction using sdk-dapp. Next we will detail each element mentioned above\n\n**Table 3**. Elements needed to build a dApp\n| # | Type | Description |\n|---|------|-------------|\n| 1 | Network | Chain configuration |\n| 2 | Provider | The signing provider for logging in and signing transactions |\n| 3 | Account | Inspecting user address and balance |\n| 4 | Transactions Manager | Sending and tracking transactions |\n| 5 | UI Components | Displaying UI information like balance, public keys etc. |\n\nSince these are mixtures of business logic and UI components, the library is split into several folders to make it easier to navigate.\nWhen inspecting the package, there is more content under `src`, but the folders of interest are:\n\n```bash\nsrc/\n├── apiCalls/ ### methods for interacting with the API\n├── constants/ ### useful constants from the ecosystem like ledger error codes, default gas limits for transactions etc.\n├── controllers/ ### business logic for UI elements that are not bound to the store\n├── managers/ ### business logic for UI elements that are bound to the store\n├── providers/ ### signing providers\n├── methods/ ### utility functions to query and update the store\n├── react/ ### react hooks to query the store\n└── store/ ### store initialization, middleware, slices, selectors and actions\n```\n\nConceptually, these can be split into 3 main parts:\n\n- First is the business logic in `apiCalls`, `constants`, `providers` and `methods`\n- Then comes the persistence layer hosted in the `store` folder, using [Zustand](https://zustand.docs.pmnd.rs/) under the hood.\n- Last are the UI components hosted in [@multiversx/sdk-dapp-ui](https://github.com/multiversx/mx-sdk-dapp-ui) with some components controlled on demand by classes defined in `controllers` and `managers`\n\nNext, we will take the elements from Table 3 and detail them in the following sections.\n\n### 1. Network\n\nThe network configuration is done in the `initApp` method, where you can make several configurations like:\n\n- specifying the environment (`devnet`, `testnet`, `mainnet`)\n- overriding certain network parameters like wallet address, explorer address etc.\n\nOnce the network is configured, the `network` slice in the store will hold the network configuration.\n\nTo query different network parameters, you can use the `getNetworkConfig` method from the `methods/network` folder.\n\n### 2. Provider\n\nThe provider is the main class that handles the signing of transactions and messages. It is initialized in the `initApp` method and can be accessed via the `getAccountProvider` method from the `providers/helpers` folder.\n\n#### Initialization\n\nAn existing provider is initialized on app load (this is take care of by `initApp`), since it restores the session from the store and allows signing transactions without the need of making a new login.\n\n#### Creating a custom provider\n\nIf you need to create a custom signing provider, make sure to extend the `IProvider` interface and implement all required methods (see example [here](https://github.com/multiversx/mx-template-dapp/tree/main/src/provider)). Next step would be to include it in the `customProviders` array in the `initApp` method or add it to the [window object](https://github.com/multiversx/mx-template-dapp/tree/main/src/initConfig). Last step is to login using the custom provider.\n\n```typescript\nconst provider = await ProviderFactory.create({\n  type: 'custom-provider'\n});\nawait provider?.login();\n```\n\n#### Accessing provider methods\n\nOnce the provider is initialized, you can get a reference to it using the `getAccountProvider` method. Then you can call the `login`, `logout`, `signTransactions`, `signMessage` methods, or other custom methods depending on the initialized provider (see ledger for example).\n\n### 3. Account\n\n#### Getting account data\n\nOnce the user logs in, a call is made to the API for fetching the account data. This data is persisted in the store and is accessible through helpers found in `methods/account`. These functions are:\n\n**Table 4**. Getting account data\n| # | Helper | Description | React hook equivalent |\n|---|------|-------------|----|\n| | `methods/account` | path | `react/account` |\n| 1 | `getAccount()` | returns all account data |`useGetAccount()` |\n| 2 | `getAddress()` | returns just the user's public key | `useGetAddress()`|\n| 3 | `getIsLoggedIn()` | returns a login status boolean | `useGetIsLoggedIn()` |\n| 4 | `getLatestNonce()` | returns the account nonce | `useGetLatestNonce()`\n\n#### Nonce management\n\n`sdk-dapp` has a mechanism that does its best to manage the account nonce. For example, if the user sends a transaction, the nonce gets incremented on the client so that if a new transaction is sent, it will have the correct increased nonce. If you want to make sure the nonce is in sync with the API account, you can call `refreshAccount()` as shown above in the **Signing transactions** section.\n\n### 4. Transactions Manager\n\n#### Overview\n\nThe `TransactionManager` is a class that handles sending and tracking transactions in the MultiversX ecosystem. It provides methods to send either single or batch transactions. It also handles tracking, error management, and toast notifications for user feedback. It is initialized in the `initApp` method and can be accessed via `TransactionManager.getInstance()`.\n\n#### Features\n\n- **Supports Single and Batch Transactions:** Handles individual transactions as well as grouped batch transactions.\n- **Automatic Tracking:** Monitors transaction status and updates accordingly through a webhook or polling fallback mechanism.\n- **Toast Notifications:** Displays status updates for user feedback, with options to disable notifications and customize toast titles.\n- **Error Handling:** Catches and processes errors during transaction submission\n\n#### Transactions Lifecycle\n\nThe transaction lifecycle consists of the following steps:\n\n1. **Creating** a `Transaction` object from `@multiversx/sdk-core`\n2. **Signing** the transaction with the initialized provider and receiving a `SignedTransactionType` object\n3. **Sending** the signed transaction using TransactionManager's `send()` function. Signed transactions can be sent in 2 ways:\n\n**Table 5**. Sending signed transactions\n| # | Signature | Method | Description |\n|---|------|-------------|-------------|\n| 1 | `send([tx1, tx2])` | `POST` to `/transactions` | Transactions are executed in parallel\n| 2 | `send([[tx1, tx2], [tx3]])` | `POST` to `/batch` | **a)** 1\u003csup\u003est\u003c/sup\u003e batch of two transactions is executed, **b)** the 2\u003csup\u003end\u003c/sup\u003e batch of one transaction waits for the finished results, **c)** and once the 1\u003csup\u003est\u003c/sup\u003e batch is finished, the 2\u003csup\u003end\u003c/sup\u003e batch is executed\n\n4. **Tracking** transactions is made by using `transactionManager.track()`. Since the `send()` function returns the same arguments it has received, the same array payload can be passed into the `track()` method. Under the hood, status updates are received via a WebSocket or polling mechanism.\n   Once a transaction array is tracked, it gets associated with a `sessionId`, returned by the `track()` method and stored in the `transactions` slice. Depending on the array's type (plain/batch), the session's status varies from initial (`pending`/`invalid`/`sent`) to final (`successful`/`failed`/`timedOut`).\n\n**Table 6**. Inspecting transaction sessions\n| # | Helper | Description | React hook equivalent |\n|---|------|-------------|----|\n| | `methods/transactions` | path | `react/transactions` |\n| 1 | `getTransactionSessions()` | returns all transaction sessions |`useGetTransactionSessions()` |\n| 2 | `getPendingTransactionsSessions()` | returns a record of pending sessions | `useGetPendingTransactionsSessions()`|\n| 3 | `getPendingTransactions()` | returns an array of signed transactions | `useGetPendingTransactions()` |\n| 4 | `getFailedTransactionsSessions()` | returns a record of failed sessions | `useGetFailedTransactionsSessions()`|\n| 5 | `getFailedTransactions()` | returns an array of failed transactions | `useGetFailedTransactions()`|\n| 6 | `getSuccessfulTransactionsSessions()` | returns a record of successful sessions | `useGetSuccessfulTransactionsSessions()`|\n| 7 | `getSuccessfulTransactions()` | returns an array of successful transactions | `useGetSuccessfulTransactions()`|\n\n5. **User feedback** is provided through toast notifications, which are triggered to inform about transactions' progress. Additional tracking details can be optionally displayed in the toast UI.\n   There is an option to add custom toast messages by using the `createCustomToast` helper.\n\n```ts\nimport { createRoot } from 'react-dom/client';\nimport { createCustomToast } from '@multiversx/sdk-dapp/out/store/actions/toasts/toastsActions';\nimport { ToastManager } from '@multiversx/sdk-dapp/out/managers/ToastManager';\n\n// by creating a custom toast element containing a component\ncreateCustomToast({\n  toastId: 'username-toast',\n  instantiateToastElement: () =\u003e {\n    const toastBody = document.createElement('div');\n    const root = createRoot(toastBody);\n    root.render(\u003cReloadButton /\u003e);\n    return toastBody;\n  }\n});\n\n// or by creating a simple custom toast\ncreateCustomToast({\n  toastId: 'custom-toast',\n  icon: 'times',\n  iconClassName: 'warning',\n  message: 'This is a custom toast',\n  title: 'My custom toast'\n});\n\n\n// closing a custom toast\nconst toastManager = ToastManager.getInstance();\ntoastManager.closeToast('custom-toast') // toastId\n\n```\n\n6. **Error Handling \u0026 Recovery** is done through a custom toast that prompts the user to take appropriate action.\n\n#### Methods\n\n---\n\n#### 1. Sending Transactions\n\nIn this way, all transactions are sent simultaneously. There is no limit to the number of transactions contained in the array.\n\n```typescript\nconst transactionManager = TransactionManager.getInstance();\nconst parallelTransactions: SignedTransactionType[] = [tx1, tx2, tx3, tx4];\nconst sentTransactions = await transactionManager.send(parallelTransactions);\n```\n\n#### 2. Sending Batch Transactions\n\nIn this sequential case, each batch waits for the previous one to complete.\n\n```typescript\nconst transactionManager = TransactionManager.getInstance();\nconst batchTransactions: SignedTransactionType[][] = [\n  [tx1, tx2],\n  [tx3, tx4]\n];\nconst sentTransactions = await transactionManager.send(batchTransactions);\n```\n\n#### 3. Tracking Transactions\n\nThe basic option is to use the built-in tracking, which displays toast notifications with default messages.\n\n```typescript\nimport { TransactionManagerTrackOptionsType } from '@multiversx/sdk-dapp/out/managers/TransactionManager/TransactionManager.types';\n\nconst options: TransactionManagerTrackOptionsType = {\n  disableToasts: false, // `false` by default\n  transactionsDisplayInfo: {\n    // optional. If left `undefined`, it will use the default messages\n    errorMessage: 'Failed adding stake',\n    successMessage: 'Stake successfully added',\n    receivedMessage: 'Stake successfully added', // optional, add it in case of multiple transactions\n    processingMessage: 'Staking in progress'\n    // submittedMessage: 'Stake submitted',\n    // timedOutMessage: 'Transaction timed out',\n    // invalidMessage: 'Invalid transaction',\n  },\n  sessionInformation: {\n    // `undefined` by default. Use to perform additional actions based on the session information\n    stakeAmount: '1000000000000000000000000'\n  },\n  onSuccess: async (sessionId) =\u003e {\n    // optional\n    // overrides the the global `onSuccess` callback set in the `initApp` method for the current session only\n    console.log('Session successful', sessionId);\n  },\n  onFail: async (sessionId) =\u003e {\n    // optional\n    console.log('Session failed', sessionId);\n  }\n};\n\nconst sessionId = await transactionManager.track(\n  sentTransactions,\n  options // optional\n);\n```\n\nIf you want to provide more human-friendly messages to your users, you can enable tracking with custom toast messages:\n\n```typescript\nconst sessionId = await transactionManager.track(sentTransactions, {\n  transactionsDisplayInfo: {\n    errorMessage: 'Failed adding stake',\n    successMessage: 'Stake successfully added',\n    processingMessage: 'Staking in progress'\n  }\n});\n```\n\n#### 3.1 Tracking transactions without being logged in\n\nIf your application needs to track transactions sent by a server and the user does not need to login to see the outcome of these transactions, there are several steps that you need to do to enable this process.\n\nStep 1. Enabling the tracking mechanism\n\nBy default the tracking mechanism is enabled only after the user logs in. That is the moment when the WebSocket connection is established. If you want to enable tracking before the user logs in, you need to call the `trackTransactions` method from the `methods/trackTransactions` folder. This method will enable a polling mechanism.\n\n```typescript\nimport { trackTransactions } from '@multiversx/sdk-dapp/out/methods/trackTransactions/trackTransactions';\n\ninitApp(config).then(async () =\u003e {\n  await trackTransactions(); // enable here since by default tracking will be enabled only after login\n  render(() =\u003e \u003cApp /\u003e, root!);\n});\n```\n\nStep 2. Tracking transactions\n\nThen, you can track transactions by calling the `track` method from the `TransactionManager` class with a plain transaction containing the transaction hash.\n\n```typescript\nimport { Transaction, TransactionsConverter } from '@multiversx/sdk-core';\n\nconst tManager = TransactionManager.getInstance();\nconst txConverter = new TransactionsConverter();\nconst transaction = txConverter.plainObjectToTransaction(signedTx);\n\nconst hash = transaction.getHash().toString(); // get the transaction hash\n\nconst plainTransaction = { ...transaction.toPlainObject(), hash };\nawait tManager.track([plainTransaction]);\n```\n\n#### 3.2 Advanced Usage\n\nIf you need to check the status of the signed transactions, you can query the store directly using the `sessionId` returned by the `track()` method.\n\n```typescript\nimport { getStore } from '@multiversx/sdk-dapp/out/store/store';\nimport { transactionsSliceSelector } from '@multiversx/sdk-dapp/out/store/selectors/transactionsSelector';\n\nconst state = transactionsSliceSelector(getStore());\nObject.entries(state).forEach(([sessionKey, data]) =\u003e {\n  if (sessionKey === sessionId) {\n    console.log(data.status);\n  }\n});\n```\n\n### 5. UI Components\n\n`sdk-dapp` needs to make use of visual elements for allowing the user to interact with some providers (like the ledger), or to display messages to the user (like idle states or toasts). These visual elements consist of webcomponents hosted in the `@multiversx/sdk-dapp-ui` package. Thus, `sdk-dapp` does not hold any UI elements, just business logic that controls external components. We can consider two types of UI components: internal and public. They are differentiated by the way they are controlled: internal components are controlled by `sdk-dapp`'s signing or logging in flows, while public components should be controlled by the dApp.\n\n#### 5.1 Public components\n\nThe business logic for these components is served by a controller. The components are:\n\n- `MvxTransactionsTable` - used to display the user's transactions\n\n```tsx\nimport { TransactionsTableController } from '@multiversx/sdk-dapp/out/controllers/TransactionsTableController';\nimport { MvxTransactionsTable } from '@multiversx/sdk-dapp-ui/react';\n\nconst processedTransactions =\n  await TransactionsTableController.processTransactions({\n    address,\n    egldLabel: network.egldLabel,\n    explorerAddress: network.explorerAddress,\n    transactions\n  });\n\n// and use like this:\n\u003cMvxTransactionsTable transactions={processedTransaction} /\u003e;\n```\n\n- `MvxFormatAmount` - used to format the amount of the user's balance\n\n```tsx\nimport { MvxFormatAmount } from '@multiversx/sdk-dapp-ui/react';\nimport { MvxFormatAmountPropsType } from '@multiversx/sdk-dapp-ui/types';\nexport { DECIMALS, DIGITS } from '@multiversx/sdk-dapp-utils/out/constants';\nimport { FormatAmountController } from '@multiversx/sdk-dapp/out/controllers/FormatAmountController';\nexport { useGetNetworkConfig } from '@multiversx/sdk-dapp/out/react/network/useGetNetworkConfig';\n\ninterface IFormatAmountProps extends Partial\u003cMvxFormatAmountPropsType\u003e {\n  value: string;\n  className?: string;\n}\n\nexport const FormatAmount = (props: IFormatAmountProps) =\u003e {\n  const {\n    network: { egldLabel }\n  } = useGetNetworkConfig();\n\n  const { isValid, valueDecimal, valueInteger, label } =\n    FormatAmountController.getData({\n      digits: DIGITS,\n      decimals: DECIMALS,\n      egldLabel,\n      ...props,\n      input: props.value\n    });\n\n  return (\n    \u003cMvxFormatAmount\n      class={props.className}\n      dataTestId={props['data-testid']}\n      isValid={isValid}\n      label={label}\n      showLabel={props.showLabel}\n      valueDecimal={valueDecimal}\n      valueInteger={valueInteger}\n    /\u003e\n  );\n};\n```\n\n#### 5.2 Internal components (advanced usage)\n\nThe way internal components are controlled is through a [pub-sub pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) called EventBus. Each webcomponent has a method of exposing its EventBus, thus allowing `sdk-dapp` to get a reference to it and use it for communication.\n\n```mermaid\nflowchart LR\n    A[\"Controller\"] \u003c--\u003e B[\"Event Bus\"] \u003c--\u003e C[\"webcomponent\"]\n```\n\n```typescript\nimport { ComponentFactory } from '@multiversx/sdk-dapp/out/utils/ComponentFactory';\n\nconst modalElement = await ComponentFactory.create\u003cLedgerConnectModal\u003e(\n  'mvx-ledger-connect-panel'\n);\nconst eventBus = await modalElement.getEventBus();\neventBus.publish('TRANSACTION_TOAST_DATA_UPDATE', someData);\n```\n\nIf you want to override private components and create your own, you can implement a similar strategy by respecting each webcomponent's API (see an interface example [here](https://github.com/multiversx/mx-sdk-dapp/blob/main/src/providers/strategies/LedgerProviderStrategy/types/ledger.types.ts)).\n\n## Debugging your dApp\n\n\u003e **Note:** For an advanced documentation on how internal flows are implemented, you can check out the [deepwiki](https://deepwiki.com/multiversx/mx-sdk-dapp) diagrams.\n\nThe recommended way to debug your application is by using [lerna](https://lerna.js.org/). Make sure you have the same package version in sdk-dapp's package.json and in your project's package.json.\n\nIf you prefer to use [npm link](https://docs.npmjs.com/cli/v11/commands/npm-link), make sure to use the `preserveSymlinks` option in the server configuration:\n\n```js\n  resolve: {\n    preserveSymlinks: true, // 👈\n    alias: {\n      src: \"/src\",\n    },\n  },\n```\n\nChrome Redux DevTools are by default enabled to help you debug your application. You can find the extension in the Chrome Extensions store.\n\nTo build the library, run:\n\n```bash\nnpm run build\n```\n\nTo run the unit tests, run:\n\n```bash\nnpm test\n```\n","funding_links":[],"categories":["TypeScript","MultiversX official"],"sub_categories":["SDKs and dev tools"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultiversx%2Fmx-sdk-dapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmultiversx%2Fmx-sdk-dapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultiversx%2Fmx-sdk-dapp/lists"}