> 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-erc-20-tokens.md).

# Shield ERC-20 tokens

Shield one or more ERC-20 tokens into RAILGUN private balances in a single transaction

### Imports

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


```

## Gas Estimate

An asynchronous function `erc20ShieldGasEstimate` that calculates the estimated gas required to execute a shielding transaction for ERC-20 tokens in the RAILGUN system. It takes as parameters the network name, a wallet instance, and a list of ERC-20 amount recipients. The function first obtains a unique shield signature for the transaction using the provided wallet. It then derives the address from which the tokens are being shielded and calls `gasEstimateForShield` to perform the gas estimation based on transaction details like the recipient information and other transaction parameters. The estimated gas is then returned, providing insights into transaction costs before execution.

```typescript
export const erc20ShieldGasEstimate = async (
  network: NetworkName,
  wallet: Wallet | HDNodeWallet,
  erc20AmountRecipients: RailgunERC20AmountRecipient[]
) => {
  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,
    erc20AmountRecipients,
    [], // nftAmountRecipients
    fromWalletAddress
  );

  return gasEstimate;
};
```

### Populate Transaction

The code block defines an asynchronous function `erc20PopulateShieldTransaction` that facilitates the preparation of a transaction for shielding ERC20 tokens using the Railgun protocol. Initially, it approves the necessary token allowances for the specified `erc20AmountRecipients` by interacting with their token contracts. It checks the current allowance and approves additional tokens if needed. The function then estimates the gas required for the shielding transaction by calling `erc20ShieldGasEstimate`. With this estimate, it retrieves gas details tailored to whether the transaction is sent using a public or private wallet. Finally, the transaction is populated using `populateShield`, which returns the transaction details including gas estimation, nullifiers, and transaction object, suitable for execution on the Ethereum network.

```typescript

export const erc20PopulateShieldTransaction = async (
  network: NetworkName,
  wallet: Wallet | HDNodeWallet,
  erc20AmountRecipients: RailgunERC20AmountRecipient[],
  sendWithPublicWallet: boolean
) => {
  // get gas estimate for tx,
  // populate tx with gas estimate
  // approve token to spender.

  // approve token to spender
  const spender = NETWORK_CONFIG[network].proxyContract;
  const tokens = erc20AmountRecipients.map((erc20AmountRecipient) => {
    return erc20AmountRecipient.tokenAddress;
  });

  for (const amountRecipient of erc20AmountRecipients) {
    const contract = new Contract(
      amountRecipient.tokenAddress,
      [
        "function allowance(address owner, address spender) view returns (uint256)",
        "function approve(address spender, uint256 amount) external returns (bool)",
      ],
      wallet
    );
    const allowance = await contract.allowance(wallet.address, spender);
    if (allowance >= amountRecipient.amount) {
      console.log("already have enough allowance");
      continue;
    }
    const tx = await contract.approve(spender, amountRecipient.amount);
    await tx.wait();
  }

  const gasEstimate = await erc20ShieldGasEstimate(
    network,
    wallet,
    erc20AmountRecipients
  );

  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,
    erc20AmountRecipients,
    [],
    gasDetails
  );

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

## Example Usage

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

  const erc20AmountRecipients = [
    serializeERC20Transfer(
      TEST_TOKEN, // WETH
      1n,
      railgunWalletAddress
    ),
  ];

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

  //   console.log("gasEstimate: ", gasEstimate);
  //   console.log("gasDetails: ", gasDetails);
  //   console.log("transaction: ", transaction);
  //   console.log("nullifiers: ", nullifiers);

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