> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Earn capabilities

> Implement executeYieldTransaction on a custom WalletProvider to enable Earn deposits, withdrawals, and reward claims.

`executeYieldTransaction` is the method the Dynamic SDK calls when [`depositToYieldVault`](/docs/javascript/reference/client/deposit-to-yield-vault), [`withdrawFromYieldVault`](/docs/javascript/reference/client/withdraw-from-yield-vault), or [`claimYieldRewards`](/docs/javascript/reference/client/claim-yield-rewards) need your wallet to sign and broadcast an [Earn](/docs/overview/yield) vault transaction. If your `WalletProvider` does not implement it, the user can connect, sign messages, and even execute swaps — but calling any Earn action throws a `WalletProviderMethodUnavailableError`.

<Note>
  Earn vault actions are EVM-only today. `executeYieldTransaction` is only
  implemented by Dynamic's built-in EVM wallet provider — a custom
  `WalletProvider` only needs this method if it also targets EVM chains.
</Note>

## What executeYieldTransaction receives

The method receives a `signingPayload` and a `walletAccount`, and must return `{ transactionHash }`. Unlike [`executeSwapTransaction`](/docs/javascript/reference/creating-extensions/wallet-provider/add-swap-capabilities), there's no optional `approvalTransactionHash` on the result — only the final transaction hash.

* `signingPayload` — `{ chainId, chainName, evmTransaction, evmApproval? }`. `evmApproval` is present only when the wallet's current ERC-20 allowance for the vault is short of the action's amount, and must be signed and sent **before** `evmTransaction`. Only [`depositToYieldVault`](/docs/javascript/reference/client/deposit-to-yield-vault) can produce an `evmApproval` — [`withdrawFromYieldVault`](/docs/javascript/reference/client/withdraw-from-yield-vault) and [`claimYieldRewards`](/docs/javascript/reference/client/claim-yield-rewards) redeem shares or rewards the wallet already holds, so they never require one.
* `walletAccount` — the connected account that should sign.

## High-level implementation

Add `executeYieldTransaction` to your `WalletProvider`:

```typescript theme={"system"}
import type { WalletProvider } from "@dynamic-labs-sdk/client/core";

const myWalletProvider: WalletProvider = {
  /* ... chain, key, metadata, connect, executeSwapTransaction, etc. ... */

  executeYieldTransaction: async ({ signingPayload, walletAccount, onStepChange }) => {
    const { evmTransaction, evmApproval } = signingPayload;

    if (evmApproval) {
      onStepChange?.('approval');
      // Replace with your wallet's native signing layer.
      await myWalletSdk.signAndSend({ transaction: evmApproval, walletAccount });
    }

    onStepChange?.('transaction');

    const transactionHash = await myWalletSdk.signAndSend({
      transaction: evmTransaction,
      walletAccount,
    });

    return { transactionHash };
  },
};
```

Your wallet's signing layer is responsible for:

1. Signing and sending `evmApproval` first, when present, and calling `onStepChange('approval')` beforehand.
2. Signing and sending `evmTransaction`, and calling `onStepChange('transaction')` beforehand.
3. Ensuring the user is on the correct network (the SDK calls `ensureCorrectActiveNetwork` before `executeYieldTransaction`, but you can validate again).
4. Returning the on-chain transaction hash of `evmTransaction` — not the approval's hash.

## Use the wallet for Earn

With `executeYieldTransaction` implemented, a consumer calls the Earn functions directly — each fetches a signing payload from the Dynamic API, then delegates signing to your provider's `executeYieldTransaction`:

```typescript theme={"system"}
import {
  claimYieldRewards,
  depositToYieldVault,
  withdrawFromYieldVault,
} from "@dynamic-labs-sdk/client";

// Deposit reports 'approval' only when the wallet's allowance is short of `amount`.
const { transactionHash: depositHash } = await depositToYieldVault({
  amount: "10.5",
  onStepChange: (step) => console.log(step), // 'approval' | 'transaction'
  vaultId,
  walletAccount,
});

// Withdraw and claim redeem shares or rewards the wallet already holds,
// so neither ever produces an approval step.
const { transactionHash: withdrawHash } = await withdrawFromYieldVault({
  amount: "5",
  vaultId,
  walletAccount,
});

const { transactionHash: claimHash } = await claimYieldRewards({
  vaultId,
  walletAccount,
});
```

`depositToYieldVault`, `withdrawFromYieldVault`, and `claimYieldRewards` all resolve the vault's contract address and asset decimals server-side, then call your provider's `executeYieldTransaction` with the resulting `signingPayload`. The only wallet-specific work is inside `executeYieldTransaction`; everything else is handled by the Dynamic SDK.

## Related

* [Build a WalletProvider](/docs/javascript/reference/creating-extensions/wallet-provider/build-wallet-provider)
* [Add swap capabilities](/docs/javascript/reference/creating-extensions/wallet-provider/add-swap-capabilities) - The equivalent method for swaps and Flow
* [`depositToYieldVault`](/docs/javascript/reference/client/deposit-to-yield-vault)
* [`withdrawFromYieldVault`](/docs/javascript/reference/client/withdraw-from-yield-vault)
* [`claimYieldRewards`](/docs/javascript/reference/client/claim-yield-rewards)
