From V2 to V3

V3 is still under development more breaking changes are going to be added here until we cut the first stable version [3.0.0]

Breaking Changes

Wallet and WalletConnectors

No more undesired prompting to reconnect or switch wallets when not required!

Now wallet can be made primary at any time without extra prompting, even if the wallet is not connected or unlocked. Users will only be prompted to connect/unlock when sending/signing a transaction, if the wallet is not connected or unlocked.

Wallet object has changed

wallet.authenticated changed to wallet.isAuthenticated wallet.connected is not an async method wallet.isConnected()

The Wallet object has changed and now contains some methods that were previously on the WalletConnector object. You can now call these methods directly from the wallet:

  • wallet.getBalance()
  • wallet.getNameService()
  • wallet.getNetwork()
  • wallet.getPublicClient()
  • wallet.getSigner()
  • wallet.getWalletClient()
  • wallet.isAvailable()
  • wallet.isConnected()
  • wallet.proveOwnership(messageToSign)
  • wallet.signMessage(messageToSign);
  • wallet.switchNetwork(networkChainId);
  • wallet.sync()

wallet.connector is not accessible anymore. You can access some of the connector methods directly from the wallet object, or through new helper methods.

Removed props

hideEmbeddedWalletTransactionUIs has been removed from useDynamicContext. This is now a toggle in the dashboard.

setPrimaryWallet has been removed. You should use useSwitchWallet instead.

Replaced props

  • setDefaultTabIndex replaced with setSelectedTabIndex in useDynamicContext

This function is used to create wallet list views.

const { setDefaultTabIndex } = useDynamicContext()

const onChangeTab = (index: number) => {
  setDefaultTabIndex(index)
}

Package restructuring

  • createWalletClientFromWallet no longer exported from sdk-react-core

The createWalletClientFromWallet function is now only available through viem-utils.

import { createWalletClientFromWallet } from '@dynamic-labs/sdk-react-core';
  • rpcProviders no longer available in the sdk-react-core package

The type DynamicRPCProviders that used to be exported from @dynamic-labs/sdk-react-core is no longer available and has been replaced with individual packages i.e. @dynamic-labs/rpc-provider-ethereum & @dynamic-labs/rpc-provider-solana:

import { useDynamicContext } from '@dynamic-labs/sdk-react-core';

const App = () => {
  const { rpcProviders } = useDynamicContext();

  console.log(rpcProviders.evmProviders);
  console.log(rpcProviders.solanaProviders);
}
  • ITurnkeySolanaSigner renamed to IEmbeddedWalletSolanaSigner and import path changed
import { ITurnkeySolanaSigner } from '@dynamic-labs/turnkey';

Events arguments

  • onAuthSuccess doesn’t return an authToken anymore

  • onEmbeddedWalletCreated returns the user instead of the authToken

You can call getAuthToken to access the authToken at any time!

Other

  • Polyfill for Solana Embedded Wallet users

You may need to polyfill the ‘crypto’ module.

webpack.config.js:

config.resolve.fallback = {
  ...config.resolve.fallback,
  crypto: require.resolve("crypto-browserify"),
};

vite.config.ts

import { nodePolyfills } from 'vite-plugin-node-polyfills';

plugins: [
      nodePolyfills({
        globals: {
          global: true,
        },
        include: [],
      }),
    ],

New Hooks

  • Re-initialize the SDK (useReinitialize)
import {
  DynamicContextProvider,
  useReinitialize,
} from '@dynamic-labs/sdk-react-core';

const ReInitButton = () => {
  const reinitialize = useReinitialize();

  return (
    <button onClick={reinitialize}>Reinitialize</button>
  );
}

const App = () => {
  return (
    <DynamicContextProvider>
      <ReInitButton />
    </DynamicContextProvider>
  )
}
  • Trigger state refresh (useRefreshUser)
import {
  DynamicContextProvider,
  useRefreshUser,
} from '@dynamic-labs/sdk-react-core';

const RefreshButton = () => {
  const refresh = useRefreshUser();

  return (
    <button onClick={refresh}>Reinitialize</button>
  );
}

const App = () => {
  return (
    <DynamicContextProvider>
      <RefreshButton />
    </DynamicContextProvider>
  )
}

From V1 to V2

Breaking changes

  • setShowAuthFlow opens dynamic profile in non-multi-wallet, logged in states

Packages

  • sdk-api to sdk-api-core

The Dynamic SDK uses a number of other Dynamic packages, among them is the sdk-api library which contains several internal APIs that are not relevant to making the SDK communicate properly with Dynamic’s backend.

Therefore we’ve created a new package called sdk-api-core which only contains endpoints and models relevant for the SDK, and this is what the V2 SDK uses.

If you need to interact with Dynamic’s backend for admin-related API calls or bulk work, among other things, you should explicitly install sdk-api, otherwise the only effect this has is lowering your bundle size!

  • Wagmi V2

We now use Wagmi V2 by default as opposed to V1 in V1 of our SDK, you can find the implementation guide here to upgrade that package implementation and integration.

  • Viem V2

Viem V2 is now the default, generally you don’t need to do anything as the SDK will install it for you but if you have Viem installed manually alongside the SDK, you’ll want to either uninstall it or ensure you’re using the latest version.

Renamed variables/props

  • useConnectWithEmailOtp to useConnectWithOtp

With the introduction of sms based login in addition to email we’ve adjusted some method naming to reflect this. Thus, useConnectWithEmailOtp becomes useConnectWithOtp.

  • fetchPublicAddress to getAddress

This renaming is simply to align with standard terminology.

  • hideEmbeddedWalletUIs prop to hideEmbeddedWalletTransactionUIs

This prop was not specific enough so we renamed it to include “Transaction” as this is exactly what it hides - the transaction confirmation screens.

  • canConnectViaEmail to requiresNonDynamicEmailOtp

This flag is actually used to decide whether a wallet connector requires an external OTP provider instead of Dynamic’s default email OTP and therefore it made sense to rename it as such.

Removed variables/props

  • isVerificationInProgress

This was a boolean, available from useDynamicContext, which indicated whether any verifications are in progress for the current user (ex. connect, sign and email login verifications). However, this leads to the need for useEffects, which the React team recommends avoiding. Therefore we’ve remove this state and request that you add listeners to our callbacks in order to trigger functionalities in an event driven manner.

  • isFullyConnected

You can now use useIsLoggedIn instead of isFullyConnected to check the user’s login status.

Replaced variables/props

  • enableForcedNetworkValidation -> networkValidationMode

The type looks like the following:

export type NetworkValidationMode = 'always' | 'sign-in' | 'never'

Use looks like this:

const settings = {
  enableForcedNetworkValidation: true,
}
  • onEmailVerificationSuccess & onEmailVerificationFailure -> onOtpVerificationResult

With the introduction of SMS authentication as well as pre-existing email authentication, it makes more sense to generalise the verification callbacks for you, rather than having 4 individual ones. Therefore we’ve created onOtpVerificationResult so you can easily listen to success and failure for email and sms.

The signature of this new callback looks like the following

export type OnOtpVerificationResult = (
  isSuccess: boolean,

  destination:
    | {
        type: Extract<OtpVerificationDestination, 'email'>
        value: string
      }
    | {
        type: Extract<OtpVerificationDestination, 'sms'>
        value: PhoneEventData
      }
) => void

The usage of the callback is outlined as such:

const DynamicSettings = {
  eventsCallbacks: {
    onEmailVerificationSuccess: (email) => handleSuccess(email),
    onEmailVerificationFailure: (email) => handleFailure(email),
  },
};

Moved variables/props

  • setShowLinkNewWalletModal

setShowLinkNewWalletModal is not part of DynamicContext anymore, but is available as part of the new useDynamicModals hook.

const {setShowLinkNewWalletModal} = useDynamicContext();

  • evmNetworks

evmNetworks now lives inside the overrides prop on the DynamicContextProvider settings object, whereas before it lived directly in the settings object.

<DynamicContextProvider
  settings={{
    environmentId: 'XXXXX',
    evmNetworks: [
      {
        blockExplorerUrls: [],
        chainId: 1,
        iconUrls: [],
        name: 'Ethereum',
        nativeCurrency: {
          decimals: 18,
          name: 'Ether',
          symbol: 'ETH',
        },
        networkId: 1,
        rpcUrls: [],
      },
    ],
  }}
>
</DynamicContextProvider>

From V1 to V1.1

There are no breaking changes or adjustments to your code required for V1.1. You can find the full list of new features associated with V1.1 here, and below we summarise the code related updates:

ERC 1155 support

Our NFT Gating feature helps you gate by NFT ownership. We’ve now added support for ERC 1155 tokens, so you can now gate by NFT ownership for both ERC 721 and ERC 1155 token types!

New webhooks added

  • user.passkeyRecovery.started
  • user.passkeyRecovery.completed
  • user.social.linked
  • user.social.unlinked
  • wallet.transferred
  • visit.created

userId in all webhook payloads

You wanted an easier way to always have the userId of the user that triggered the event - now we also include the userId of the trigger in all webhook event objects!

New hooks & methods

  • showDynamicUserProfile Currently the setShowDynamicUserProfile method exists on useDynamicContext which helps you trigger the user profile modal, however you had no way of knowing if the modal was open or not. Now you can use the showDynamicUserProfile boolean to get this information.
export const Example = () => {
  const { showDynamicUserProfile } = useDynamicContext()
  React.useEffect(() => {
    if (showDynamicUserProfile) {
      /* On widget opens */
    } else {
      /* On widget closes */
    }
  }, [showDynamicUserProfile])
  return null
}
  • useConnectWithEmailOtp Now you can handle headless email signup with the useConnectWithEmailOtp hook! It exposes connectWithEmail and verifyOneTimePassword functions. It supports both Dynamic native login and our Magic integration.

  • setShowLinkNewWalletModal This new method comes as part of useDynamicContext and allows you to trigger the link new wallet method programmatically.

const LinkNewWalletButton = () => {
  const { setShowLinkNewWalletModal } = useDynamicContext()
  return (
    <button onClick={() => setShowLinkNewWalletModal(true)}>
      Link a new wallet
    </button>
  )
}
  • setAuthMode Previously, you could set the auth mode via the initialAuthenticationMode prop on DynamicContextProvider but this would be set in stone once the app loads. Now you can also set it programmatically via the setAuthMode method on useDynamicContext.
const Example = () => {
  const { setAuthMode } = useDynamicContext()
  return (
    <button onClick={() => setAuthMode('connect-only')}>Connect Only</button>
  )
}

New callbacks

  • onAuthFlowCancel This callback is triggered when the user cancels the auth flow before successful completion. It will get called alongside onAuthFlowClose.

Extra text in the signup/login UI

  • Additional views section for extra text in the signup/login UI If you use Programmable Views, you can now insert extra text:
views: [
  {
    type: 'login',
    sections: [
      { type: 'text', label: 'Intro Text', alignment: 'center' },
      ...
    ],
  },
],

Multi-wallet prompts without userProfile widget

This allows you to use the multi wallet prompts without needing the full user profile which in which these prompts are normally bundled.

From V0.19 to V1

This upgrade guide is specific to implementing the SDK itself, you can also find the features that ship with V1 here.

Breaking Changes

userWallets hooks

  • connectedWallets , secondaryWallets and linkedWallets all been removed in favor of userWallets hook. See here for more info.
import { useUserWallets, getNetwork } from '@dynamic-labs/sdk-react-core';

const App = () => {
const userWallets = useUserWallets();

useEffect(() => {
  userWallets.forEach(async ({ connector }) => {
  const network = await getNetwork(connector);
        ...
      });
}, [userWallets]);

...
}

EthereumSmartWalletConnectors -> ZeroDevSmartWalletConnectors

  • (v1 alpha -> v1) EthereumSmartWalletConnectors is now renamed to ZeroDevSmartWalletConnectors. You use this connector when you want to use AA wallets.
import {DynamicContextProvider} from "@dynamic-labs/sdk-react-core";
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';
import { ZeroDevSmartWalletConnectors } from '@dynamic-labs/ethereum-aa';

const App = () => (

  <DynamicContextProvider
    settings={{
      ...
      walletConnectors: [ EthereumWalletConnectors, ZeroDevSmartWalletConnectors ],
      ...
    }}>
    <DynamicWidget />
  </DynamicContextProvider>
);

export default App;

wallets -> walletConnectorOptions

  • Wallets property returned by useDynamicContext now renamed to walletConnectorOptions
import { useDynamicContext } from "@dynamic-labs/sdk-react-core";

const App = () => {
const { walletConnectorOptions } = useDynamicContext();
return (

<div>
  {walletConnectorOptions.map((wallet) => (
    <div>{wallet.name}</div>
  ))}
</div>
); };

export default App
;````

</Tab >

<Tab title="Before">
```jsx
import { useDynamicContext } from "@dynamic-labs/sdk-react-core";

const App = () => {
const { wallets } = useDynamicContext();
return (

<div>
  {wallets.map((wallet) => (
    <div>{wallet.name}</div>
  ))}
</div>
); };

export default App;

walletsByChain -> bridgeChains

  • walletsByChain has been renamed to bridgeChains
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";

const App = () => {
return (

<DynamicContextProvider
  settings={{
    environmentId: 'ENV_ID',
    bridgeChains: [
      {
        chain: 'EVM',
      },
    ],
  }}
>
  <DynamicWidget />
</DynamicContextProvider>
); };

export default App;

Non Breaking Changes

  • Turnkey wallets are now created as Turnkey HD wallets.

New Features

  • eip6963 is now fully supported without any need for changes on your end!

  • Listening to changes in wallet connectors is now supported via a hook called useWalletConnectorEvent. See here for more info.

  • You can now trigger the onramp flow programmatically using the useFunding hook. See here for more info.

  • Support for account recovery via a hook has been added. See here for more info.

  • We now generate HD wallets by default, there is nothing you need to do to take advantage of this.

  • You can now generate AA wallets (SCWs) using our AA integrations. See here for more info.

  • All of the copy which is used in the UI from the SDK is now completely editable. See here for more info.

  • You can control what kind of signup/login options are shown in your UI on a programmatic basis regardless of what is enabled in the dashboard. See here for more info.

  • Embedded wallets has been split up into the generation step and the claim step which means you can now give a user a wallet but without them adding a passkey until they make their first transaction. See here for more info.

  • Along the same lines as above, you can also pregenerate a wallet for a user without any interaction from them by using our API directly. See here for more info.

  • Webhooks are now offered out of the box! You do not need to make any SDK changes to take advantage of this. See here for more info.

From V0.18 to V0.19

Summary

This upgrade guide is specific to implementing the SDK itself, you can also find the features that ship with V19 here.

There are a number of breaking changes in v0.19, mainly to the way the SDK is structured. To upgrade you should follow three steps, which are outlined in the breaking changes section below.

1

Switch to sdk-react-core

Uninstall sdk-react (if used) and install the latest sdk-react-core.

3

Viem as default

If you’re happy for Viem to be the default instead of Ethers, do nothing. Otherwise, use the Ethers extension.

Breaking Changes

sdk-react -> sdk-react-core

Previously you could use the SDK in two ways. The first was by installing sdk-react which came with all of the possible WalletConnectors pre-bundled. The second was by installing sdk-react-core and then adding WalletConnectors yourself alongside it.

While the first was helpful in getting started, the general feedback was that the bundle size was too large. So we’ve decided to remove the sdk-react package and make sdk-react-core the main way of installing the SDK.

To get started in this way, you should uninstall sdk-react and install sdk-react-core instead. If you’re already using sdk-react-core, it’s worth upgrading it to the latest version.

npm uninstall @dynamic-labs/sdk-react

npm install @dynamic-labs/sdk-react-core

WalletConnectors

As mentioned above, sdk-react-core doesn’t come with any WalletConnectors pre-bundled.

There are also no more all packages available.

You should install them according to the table below.

Package NameChainWalletConnector to include
@dynamic-labs/ethereumEVMEthereumWalletConnectors
@dynamic-labs/algorandALGOAlgorandWalletConnectors
@dynamic-labs/solanaSOLSolanaWalletConnectors
@dynamic-labs/flowFLOWFlowWalletConnectors
@dynamic-labs/starknetSTARKStarknetWalletConnectors
@dynamic-labs/cosmosCOSMOSCosmosWalletConnectors
EVM Addon Wallets
Package NameWhich WalletsWalletConnector to include
@dynamic-labs/magicmagicMagicWalletConnectors
@dynamic-labs/blocto-evmbloctoBloctoEvmWalletConnectors

Magic and Blocto were previously available via the ethereum-all package which is now deprecated, please note that you will no longer get Magic & Blocto with the ethereum package - use the above packages instead.

Here’s an example for Ethereum & Flow:

npm install @dynamic-labs/ethereum @dynamic-labs/flow

Using WalletConnectors

Using WalletConnectors looks like the following (ethereum and flow example):

import { EthereumWalletConnectors } from "@dynamic-labs/ethereum";
import { FlowWalletConnectors } from "@dynamic-labs/flow";


const App = () => (
  <DynamicContextProvider
     settings={{
       ...
       walletConnectors: [ EthereumWalletConnectors, FlowWalletConnectors ],
  		 ...
    }}>
    <DynamicWidget />
  </DynamicContextProvider>
);

export default App;

Ethers -> Viem

We’ve also changed the way we interact with the BlockChain RPC and the Wallet. Previously we used Ethers.js by default and gave you a Viem version if you needed, but with Viem now rising further in popularity and functionality, we’ve now moved to Viem as the default library.

Please not that since Viem is now a peer dependancy of the SDK, it will be installed even if you use Ethers.

If you’re happy to use Viem, this should not have much of an effect on you. If you would still like to use Ethers or do not want to migrate your own application to using Viem, we have provided an extension for accessing Ethers within our Connectors:

npm i @dynamic-labs/ethers-v5
import { EthersExtension } from '@dynamic-labs/ethers-v5'

return (
  <DynamicContextProvider
    settings={{
      environmentId: 'XXXXX',
      walletConnectorExtensions: [EthersExtension],
    }}
  >
    <App />
  </DynamicContextProvider>
)

You can then access the signer like so:

const signer = await primaryWallet.connector.ethers?.getSigner()

If you want to use Ethers V6 instead of V5, it’s as simple as using @dynamic-labs/ethers-v6 instead of @dynamic-labs/ethers-v5.

WalletConnector methods naming

Since the move to Viem, we have also updated the method names on the WalletConnector as they previously used Ethers Terminology.

V0.18V0.19
getWeb3Provider()getPublicClient()
getRpcProvider()getWalletClient()

onConnectSuccess -> onConnect

We’ve also renamed the onConnectSuccess callback to onConnect.

WalletIcon

V0.18V0.19
<WalletIcon walletName={normalizeWalletName(walletConnector.name)}<WalletIcon walletKey={walletConnector.key}
npm i @dynamic-labs/wallet-book
import { useDynamicContext } from '@dynamic-labs/sdk-react-core'
import { WalletIcon } from '@dynamic-labs/wallet-book'

const { primaryWallet } = useDynamicContext()

return <WalletIcon walletKey={primaryWallet.connector.key} />

Non-breaking changes

New Callbacks added

  • onSignedMessage

  • onEmailVerificationSuccess (since replaced with “onotpverificationresult”)

  • onEmailVerificationFailure (since replaced with “onotpverificationresult”)

New Hooks added

From V0.17 to V0.18

Summary

There are no major breaking changes in V0.18. There are a few minor changes in V0.18.x, which you can find below.

You can also find the features that ship with V0.18 here.

Updates to API URIs

Our api is served now from www.dynamicauth.com instead of www.dynamic.xyz, which should reduce issues for end users behind specific firewall providers.. Please update any rules and validations that you might have on the dynamic.xyz URIs.

Changes to ​​DynamicContextProvider

Prop rename from: displayTermsOfService to: displaySiweStatement.

This affects DynamicContextProvider. If you’re passing displayTermsOfService to DynamicContextProvider, you should update your code like so:

<DynamicContextProvider
  settings={{
    environmentId: "1234abcd-1234-abcd-1234-abcd12343abc",
    displayTermsOfService: false,
    ...
  }}
>
</DynamicContextProvider>

Multiwallet prop has been removed.

If you have multiwallet enabled please enable it in your dashboard:

<DynamicContextProvider
  settings={{
    multiWallet: true,
    ...
  }}
>
  {...}
</DynamicContextProvider>

Changes to DynamicContext

ConnectedWallets

connectedWallets now represents all the wallets that are actually connected

const { connectedWallets } = useDynamicContext()
LinkedWallets

Used to be called ConnectedWallets now only represents that wallets that are linked to the account (only relevant to connect-and-auth flow)

const { linkedWallets } = useDynamicContext()

Updates to Walletbook

If you have a dependancy on @dynamic-labs/walletbook < v0.19, please remove it from your dependancies as it should now be included by default alongside the sdk-react package.

From V0.16 to V0.17

Breaking Changes

  • In favor of supporting MagicLink Wallets we removed the support for Fortmatic.

  • chainName on EvmNetwork is deprecated in favor of name. If you’re passing evmNetworks to DynamicContextProvider or DynamicWagmiConnector, you should update your code like so:

<DynamicContextProvider
  settings={{
    environmentId: 'YOUR_ENV_ID',
    evmNetworks: [
      {
        blockExplorerUrls: [],
        chainId: 1,
        iconUrls: [],
     -  chainName: 'Ethereum',
     +  name: 'Ethereum',
        nativeCurrency: {
          decimals: 18,
          name: 'Ether',
          symbol: 'ETH',
        },
        networkId: 1,
        rpcUrls: [],
      },
    ],
  }}
>
  <HomePage />
</DynamicContextProvider>

chainName is a deprecated field on the EVMchain (and will be removed on v18), but if you pass a custom EVM network you will need to change to name.

  • the multiWallet prop on DynamicContextProvider is deprecated in favor of the Dashboard settings. See here for more info.

From V0.15 to V0.16

Breaking Change

  • With the introduction of email login and social verification we moved to verifiedCredentials instead of blockchainAccounts. blockChainAccounts was removed from the user’s object.

From V0.14 to V0.15

Breaking Change

  • Based on your feedback, our team has been hard at work to completely redesign our SDK UI and move it to ShadowDom. Now in addition, to the default customizations that we provide in the our admin dashboard, you have full control and ability to customize any element in the Dynamic’s SDK to your liking. If you previously used any CSS Classes to override our previous SDK modal you will need to update them to the current CSS classes. For more info see: Custom CSS.

  • As we introduced more callbacks, we now require all the callbacks to be nested under events. See Callbacks for more info.

  • We removed user.walletPublicKey, instead please use primaryWallet.address, which you can access from useDynamicContext.