# Unshield ERC-20 tokens

*Unshielding requires you to "Generate Proof" and, optionally, make use of "Relayers": See UX for Private Transactions* [*UX for Private Transactions* ](/developer-guide/wallet/transactions/ux-private-transactions.md)

Unshield multiple ERC-20 tokens into a public wallet in a single transaction.

### Imports

```typescript
import {
  calculateGasPrice,
  NetworkName,
  TXIDVersion,
  type RailgunERC20AmountRecipient,
  type RailgunWalletInfo,
  type TransactionGasDetails,
} from "@railgun-community/shared-models";
import {
  gasEstimateForUnprovenUnshield,
  generateUnshieldProof,
  populateProvedUnshield,
} from "@railgun-community/wallet";
import {
  getGasDetailsForTransaction,
  getOriginalGasDetailsForTransaction,
  serializeERC20Transfer,
} from "../util";
import { TEST_NETWORK, TEST_TOKEN } from "../../utils/constants";
import { getProviderWallet } from "../../utils/provider";
```

### Gas Estimate

```typescript
export const erc20UnshieldGasEstimate = async (
  network: NetworkName,
  railgunWalletID: string,
  encryptionKey: string,
  erc20AmountRecipients: RailgunERC20AmountRecipient[]
) => {
  const sendWithPublicWallet = true;
  const originalGasDetails = await getOriginalGasDetailsForTransaction(
    network,
    sendWithPublicWallet
  );
  // dont setup broadcaster connection for simplicity.
  const feeTokenDetails = undefined;
  console.log("unshield originalGasDetails: ", originalGasDetails);

  const { gasEstimate } = await gasEstimateForUnprovenUnshield(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    railgunWalletID,
    encryptionKey,
    erc20AmountRecipients,
    [], // nft amount recipients
    originalGasDetails,
    feeTokenDetails,
    sendWithPublicWallet
  );

  return gasEstimate;
};
```

### Generate Proof

```typescript
export const erc20UnshieldGenerateProof = async (
  encryptionKey: string,
  network: NetworkName,
  railgunWalletID: string,
  tokenAmountRecipients: RailgunERC20AmountRecipient[],
  overallBatchMinGasPrice: bigint,
  sendWithPublicWallet: boolean = true,
  broadcasterFeeERC20AmountRecipient:
    | RailgunERC20AmountRecipient
    | undefined = undefined
) => {
  const progressCallback = (progress: number) => {
    // Handle proof progress (show in UI).
    // Proofs can take 20-30 seconds on slower devices.
    console.log("Unshield ERC20 Proof progress: ", progress);
  };
  await generateUnshieldProof(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    railgunWalletID,
    encryptionKey,
    tokenAmountRecipients,
    [], // nft amount recipients
    broadcasterFeeERC20AmountRecipient,
    sendWithPublicWallet,
    overallBatchMinGasPrice,
    progressCallback
  );
};

```

### Populate Transaction

```typescript

export const erc20UnshieldPopulateTransaction = async (
  network: NetworkName,
  railgunWalletID: string,
  tokenAmountRecipients: RailgunERC20AmountRecipient[],
  overallBatchMinGasPrice: bigint,
  transactionGasDetails: TransactionGasDetails,
  sendWithPublicWallet: boolean = true,
  broadcasterFeeERC20AmountRecipient:
    | RailgunERC20AmountRecipient
    | undefined = undefined
) => {
  const populateResponse = await populateProvedUnshield(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    railgunWalletID,
    tokenAmountRecipients,
    [], // nftAmountRecipients
    broadcasterFeeERC20AmountRecipient,
    sendWithPublicWallet,
    overallBatchMinGasPrice,
    transactionGasDetails
  );

  return populateResponse;
};

```

### Example Usage

```typescript
export const TEST_ERC20Unshield = async (
  encryptionKey: string,
  railgunWalletInfo: RailgunWalletInfo
) => {
  console.log("TEST_ERC20Unshield");
  const { wallet } = getProviderWallet();
  const erc20AmountRecipients: RailgunERC20AmountRecipient[] = [
    serializeERC20Transfer(
      TEST_TOKEN, // WETH
      1n,
      wallet.address
    ),
  ];

  const gasEstimate = await erc20UnshieldGasEstimate(
    TEST_NETWORK,
    railgunWalletInfo.id,
    encryptionKey,
    erc20AmountRecipients
  );

  console.log("ERC20 UNSHIELD gasEstimate: ", gasEstimate);

  // generate unshield proof
  await erc20UnshieldGenerateProof(
    encryptionKey,
    TEST_NETWORK,
    railgunWalletInfo.id,
    erc20AmountRecipients,
    1n
  );

  const transactionGasDetails = await getGasDetailsForTransaction(
    TEST_NETWORK,
    gasEstimate,
    true,
    wallet
  );

  const overallBatchMinGasPrice = await calculateGasPrice(
    transactionGasDetails
  );

  // populate tx

  const transaction = await erc20UnshieldPopulateTransaction(
    TEST_NETWORK,
    railgunWalletInfo.id,
    erc20AmountRecipients,
    overallBatchMinGasPrice,
    transactionGasDetails
  );

  console.log("ERC20 UNSHIELD transaction", transaction);
  // send unshield tx
  // submission via self-signed tx or public-broadcaster
};
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.railgun.org/developer-guide/wallet/transactions/unshielding/unshield-erc-20-tokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
