Unshield base token

Unshielding requires you to "Generate Proof" and, optionally, make use of "Relayers": See UX for Private Transactions UX for Private Transactions

Unshield only the base token for a network (eg. ETH) from shielded wETH in a single transaction.

Base tokens cannot be shielded by themselves, as they are not ERC-20 tokens. They must be shielded as a wrapped token, eg. wETH for the Ethereum network. You can choose to unshield a wrapped base token (like wETH) from a user's private balance to the equivalent base token.

Base token unshields are executed as a multi call through RAILGUN Relay Adapt, which unwraps the wETH into ETH at a 1:1 ratio and unshields the result into a public balance. This transaction is performed in isolation and cannot be paired with ERC-20 unshields.

Imports

import {
  calculateGasPrice,
  TXIDVersion,
  type NetworkName,
  type RailgunERC20Amount,
  type RailgunERC20AmountRecipient,
  type RailgunWalletInfo,
  type TransactionGasDetails,
} from "@railgun-community/shared-models";
import { TEST_NETWORK, TEST_TOKEN } from "../../utils/constants";
import {
  getGasDetailsForTransaction,
  getOriginalGasDetailsForTransaction,
} from "../util";
import {
  gasEstimateForUnprovenUnshieldBaseToken,
  generateUnshieldBaseTokenProof,
  populateProvedUnshieldBaseToken,
} from "@railgun-community/wallet";
import { getProviderWallet } from "../../utils/provider";

Gas Estimate

export const ethUnshieldGasEstimate = async (
  network: NetworkName,
  railgunWalletID: string,
  encryptionKey: string,
  erc20AmountRecipients: RailgunERC20Amount,
  destinationAddress: string
) => {
  const sendWithPublicWallet = true;
  const originalGasDetails = await getOriginalGasDetailsForTransaction(
    network,
    sendWithPublicWallet
  );

  // dont setup broadcaster connection for simplicity.
  const feeTokenDetails = undefined;
  console.log("unshield ETH originalGasDetails: ", originalGasDetails);

  const { gasEstimate } = await gasEstimateForUnprovenUnshieldBaseToken(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    destinationAddress,
    railgunWalletID,
    encryptionKey,
    erc20AmountRecipients,
    originalGasDetails,
    feeTokenDetails,
    sendWithPublicWallet
  );

  return gasEstimate;
};

Generate Proof

export const ethUnshieldGenerateProof = async (
  encryptionKey: string,
  network: NetworkName,
  railgunWalletID: string,
  destinationAddress: string,
  tokenAmountRecipients: RailgunERC20Amount,
  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 ETH Proof progress: ", progress);
  };

  await generateUnshieldBaseTokenProof(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    destinationAddress,
    railgunWalletID,
    encryptionKey,
    tokenAmountRecipients,
    broadcasterFeeERC20AmountRecipient,
    sendWithPublicWallet,
    overallBatchMinGasPrice,
    progressCallback
  );
};

Populate Transaction

export const ethUnshieldPopulateTransaction = async (
  network: NetworkName,
  railgunWalletID: string,
  destinationAddress: string,
  tokenAmountRecipients: RailgunERC20Amount,
  overallBatchMinGasPrice: bigint,
  transactionGasDetails: TransactionGasDetails,
  sendWithPublicWallet: boolean = true,
  broadcasterFeeERC20AmountRecipient:
    | RailgunERC20AmountRecipient
    | undefined = undefined
) => {
  const populateResponse = await populateProvedUnshieldBaseToken(
    TXIDVersion.V2_PoseidonMerkle,
    network,
    destinationAddress,
    railgunWalletID,
    tokenAmountRecipients,
    broadcasterFeeERC20AmountRecipient,
    sendWithPublicWallet,
    overallBatchMinGasPrice,
    transactionGasDetails
  );
  return populateResponse;
};

Example Usage

export const TEST_ETHUnshield = async (
  encryptionKey: string,
  railgunWalletInfo: RailgunWalletInfo
) => {
  const { wallet } = getProviderWallet();

  //
  const wrappedERC20Amount: RailgunERC20Amount = {
    tokenAddress: TEST_TOKEN, // wETH
    amount: 1n, //
  };

  // gas estimate
  const gasEstimate = await ethUnshieldGasEstimate(
    TEST_NETWORK,
    railgunWalletInfo.id,
    encryptionKey,
    wrappedERC20Amount,
    wallet.address
  );

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

  // generate eth unshield proof
  await ethUnshieldGenerateProof(
    encryptionKey,
    TEST_NETWORK,
    railgunWalletInfo.id,
    wallet.address,
    wrappedERC20Amount,
    1n // originalBatchMinGasPrice
  );
  const transactionGasDetails = await getGasDetailsForTransaction(
    TEST_NETWORK,
    gasEstimate,
    true,
    wallet
  );

  const overallBatchMinGasPrice = await calculateGasPrice(
    transactionGasDetails
  );

  // populate tx
  const transaction = await ethUnshieldPopulateTransaction(
    TEST_NETWORK,
    railgunWalletInfo.id,
    wallet.address,
    wrappedERC20Amount,
    overallBatchMinGasPrice,
    transactionGasDetails
  );
  console.log("ETH UNSHIELD transaction", transaction);
};

Last updated