Summary

Dynamic provides a simple and easy-to-use interface for users to send tokens to any address on EVM and Solana (available on the latest V3 of the SDK).

This allows your users to easily move funds from their wallets without leaving the dapp, while removing the burden of creating send flows and gas calculations across all EVM networks and Solana for you as a developer. Note that for Solana, we also include a priority fee to improve success rates in case of congestion on the network.

You have two options to surface this UI to your end users: the first is within the Dynamic Widget, and the second is programmatically opening the UI from your own site. We cover both options here.

Within Dynamic Widget/Embedded Widget

Add the widget

Simply add the Dynamic Widget or Dynamic Embedded Widget to your dapp and the Send Token UI will be available to your users.

import { DynamicWidget, DynamicEmbeddedWidget } from "@dynamic-labs/sdk-react-core";

// COMPONENT INSIDE TREE WHERE DYNAMIC CONTEXT IS AVAILABLE
const Main => {
    return (
        <div>
            // ONLY USE ONE OR THE OTHER
            <DynamicWidget />
            <DynamicEmbeddedWidget />
        </div>
    )
}

End user experience

Once logged in, on the Wallets screen of the widget, you will notice a “Send” button. Clicking on this button will take you to the Send Token UI.

You can then choose from any available token in your wallet, add an amount and recipient address, then preview the transaction before confirming.

Standalone UI (useSendBalance)

You can use our useSendBalance hook to trigger the Send Balance UI and optionally, prepopulate the form for the user.

How it works

The useSendBalance hook depends on the DynamicContextProvider, so it has to be used as a child of the Dynamic context. When you use the hook, you will get a function named open. That method accepts the follow options:

ParameterTypeDescription
recipientAddressStringThe initial recipient address
valueethers.BigNumberThe initial transaction amount

The open function will return a promise; If successful, the promise will be resolved with the transaction; if not successful, the promise will be rejected accompanied by the error collected from the provider.

Here is an example of a custom Send button

import { useSendBalance } from "@dynamic-labs/sdk-react-core";

const MySendButton = () => {
  const { open } = useSendBalance();

  return <button onClick={() => open()}>Send</button>;
};

From this example, when the user clicks the button, they will be prompted to fill the amount and recipient fields, review the transaction, and they will see a confirmation at the end of the flow.

For the second example, we will pre-populate the recipient and amount fields for the user.

import { useSendBalance } from "@dynamic-labs/sdk-react-core";
import { ethers } from "ethers";

const MySendButton = () => {
  const { open } = useSendBalance();

  const onCickSend = async () => {
    try {
      const tx = await open({
        recipientAddress: "<address>",
        value: ethers.utils.parseEther("1"),
      });
    } catch (err) {
      // Handle the promise rejection
    }
  };

  return <button onClick={onCickSend}>Send</button>;
};

Here, when the user clicks the button, they will be prompted with the same UI, but now it will be pre-populated with the recipient address and amount.