# 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: 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/shielding/shield-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.
