# Unshield NFTs

*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-721 tokens into a public wallet in a single transaction.

### Imports

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

### Gas Estimate

```typescript
export const erc721UnshieldGasEstimate = async (
  network: NetworkName,
  railgunWalletID: string,
  encryptionKey: string,
  erc721AmountRecipients: RailgunNFTAmountRecipient[]
) => {
  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
    erc721AmountRecipients,
    originalGasDetails,
    feeTokenDetails,
    sendWithPublicWallet
  );

  return gasEstimate;
};

```

### Generate Proof

```typescript
export const erc721UnshieldGenerateProof = async (
  encryptionKey: string,
  network: NetworkName,
  railgunWalletID: string,
  erc721AmountRecipients: RailgunNFTAmountRecipient[],
  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 ERC721 Proof progress: ", progress);
  };

  await generateUnshieldProof(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    railgunWalletID,
    encryptionKey,
    [],
    erc721AmountRecipients, // nft amount recipients
    broadcasterFeeERC20AmountRecipient,
    sendWithPublicWallet,
    overallBatchMinGasPrice,
    progressCallback
  );
};
```

### Populate Transaction

```typescript
export const erc721UnshieldPopulateTransaction = async (
  network: NetworkName,
  railgunWalletID: string,
  erc721AmountRecipients: RailgunNFTAmountRecipient[],
  overallBatchMinGasPrice: bigint,
  transactionGasDetails: TransactionGasDetails,
  sendWithPublicWallet: boolean = true,
  broadcasterFeeERC20AmountRecipient:
    | RailgunERC20AmountRecipient
    | undefined = undefined
) => {
  const populateResponse = await populateProvedUnshield(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    railgunWalletID,
    [], // erc20AmountRecipients
    erc721AmountRecipients,
    broadcasterFeeERC20AmountRecipient,
    sendWithPublicWallet,
    overallBatchMinGasPrice,
    transactionGasDetails
  );

  return populateResponse;
};
```

### Example Usage

```typescript
export const TEST_ERC721Unshield = async (
  encryptionKey: string,
  railgunWalletInfo: RailgunWalletInfo
) => {
  console.log("TEST_ERC721Unshield");
  const { wallet } = getProviderWallet();
  const erc721AmountRecipients: RailgunNFTAmountRecipient[] = [
    serializeERC721Transfer(TEST_NFT_ADDRESS, TEST_NFT_SUBID, wallet.address),
  ];

  const gasEstimate = await erc721UnshieldGasEstimate(
    TEST_NETWORK,
    railgunWalletInfo.id,
    encryptionKey,
    erc721AmountRecipients
  );

  console.log("ERC721 UNSHIELD gasEstimate");

  // generate erc721 unshield proof
  await erc721UnshieldGenerateProof(
    encryptionKey,
    TEST_NETWORK,
    railgunWalletInfo.id,
    erc721AmountRecipients,
    1n
  );

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

  const overallBatchMinGasPrice = await calculateGasPrice(
    transactionGasDetails
  );

  const transaction = await erc721UnshieldPopulateTransaction(
    TEST_NETWORK,
    railgunWalletInfo.id,
    erc721AmountRecipients,
    overallBatchMinGasPrice,
    transactionGasDetails
  );

  console.log("ERC721 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-nfts.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.
