> For the complete documentation index, see [llms.txt](https://docs.railgun.org/developer-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.railgun.org/developer-guide/wallet/transactions/shielding/shield-nfts.md).

# Shield NFTs

Shield one or many ERC-721 tokens into RAILGUN private balances in a single transaction. ERC-1155 not supported at this time.

### Imports

```typescript
import {
  NETWORK_CONFIG,
  TXIDVersion,
  type NetworkName,
  type RailgunNFTAmountRecipient,
} from "@railgun-community/shared-models";
import {
  gasEstimateForShield,
  populateShield,
} from "@railgun-community/wallet";
import { type Wallet, type HDNodeWallet, Contract, ZeroAddress } from "ethers";
import {
  getGasDetailsForTransaction,
  getShieldSignature,
  serializeERC721Transfer,
} from "../util";
import {
  TEST_NETWORK,
  TEST_NFT_ADDRESS,
  TEST_NFT_SUBID,
} from "../../utils/constants";
import { getProviderWallet } from "../../utils/provider";
```

### Gas Estimate

The  `erc721ShieldGasEstimate` function calculates the estimated gas cost required for shielding a given amount of ERC-721 tokens. It uses the network and wallet information to derive a shield signature from the sender's wallet address, and the intended token recipients to compute the gas estimate.

```typescript
export const erc721ShieldGasEstimate = async (
  network: NetworkName,
  wallet: Wallet | HDNodeWallet,
  erc721AmountRecipients: RailgunNFTAmountRecipient[]
) => {
  const shieldPrivateKey = await getShieldSignature(wallet);

  // Address of public wallet we are shielding from
  const fromWalletAddress = wallet.address;

  const { gasEstimate } = await gasEstimateForShield(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    shieldPrivateKey,
    [],
    erc721AmountRecipients, // nftAmountRecipients
    fromWalletAddress
  );

  return gasEstimate;
};
```

### Populate Transaction

The `erc721PopulateShieldTransaction` function constructs a transaction that authorizes and transfers the ERC-721 tokens to the RAILGUN shield. It checks if each token's transfer approval has been granted to the network's proxy contract and processes the transactions accordingly. It then calculates the gas details and populates the transaction with necessary privacy protocol data before returning the transaction information.

```typescript
export const erc721PopulateShieldTransaction = async (
  network: NetworkName,
  wallet: Wallet | HDNodeWallet,
  erc721AmountRecipients: RailgunNFTAmountRecipient[],
  sendWithPublicWallet: boolean
) => {
  const spender = NETWORK_CONFIG[network].proxyContract;

  for (const amountRecipient of erc721AmountRecipients) {
    const contract = new Contract(
      amountRecipient.nftAddress,
      [
        "function getApproved(uint256 tokenId) view returns (address)",
        "function approve(address to, uint256 tokenId) external returns (bool)",
      ],
      wallet
    );
    const allowance = await contract.getApproved(amountRecipient.tokenSubID);
    if (allowance === ZeroAddress) {
      throw new Error("ERC721 Not minted.");
    }
    if (allowance.toLowerCase() == spender.toLowerCase()) {
      console.log("already have enough allowance");
      continue;
    }

    const tx = await contract.approve(spender, amountRecipient.tokenSubID);
    await tx.wait();
  }

  const gasEstimate = await erc721ShieldGasEstimate(
    network,
    wallet,
    erc721AmountRecipients
  );

  const shieldPrivateKey = await getShieldSignature(wallet);

  const gasDetails = await getGasDetailsForTransaction(
    network,
    gasEstimate,
    sendWithPublicWallet,
    wallet
  );
  const { transaction, nullifiers } = await populateShield(
    TXIDVersion.V2_PoseidonMerkle, // this is for V2 of the railgun protocol
    network,
    shieldPrivateKey,
    [],
    erc721AmountRecipients,
    gasDetails
  );

  return {
    gasEstimate,
    gasDetails,
    transaction,
    nullifiers,
  };
};
```

### Example Usage

Finally, the `TEST_shieldERC721` function demonstrates how to use these processes by shielding an example NFT to a specified RAILGUN wallet address. It showcases assembling the transaction, sending it with the wallet, and handling the transaction receipt.

```typescript
export const TEST_shieldERC721 = async (railgunWalletAddress: string) => {
  const { wallet } = getProviderWallet();

  const nftAddress = TEST_NFT_ADDRESS;
  const tokenSubID = TEST_NFT_SUBID;
  const erc721AmountRecipients = [
    serializeERC721Transfer(nftAddress, tokenSubID, railgunWalletAddress),
  ];

  const { gasEstimate, gasDetails, transaction, nullifiers } =
    await erc721PopulateShieldTransaction(
      TEST_NETWORK,
      wallet,
      erc721AmountRecipients,
      true
    );

  const tx = await wallet.sendTransaction(transaction);
  console.log("tx: ", tx);
  await tx.wait();
};
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.railgun.org/developer-guide/wallet/transactions/shielding/shield-nfts.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
