💻
Developer Guide
  • Wallet SDK
    • Wallet Overview
    • Getting Started
      • 1. Start the RAILGUN Privacy Engine
      • 2. Build a persistent store for artifact downloads
      • 3. Load a Groth16 prover for each platform
      • 4. Add networks and RPC providers
      • 5. Set up a debug logger
    • Private Wallets
      • RAILGUN Wallets
      • View-Only Wallets
      • Encryption Keys
    • Private Balances
      • Balance and Sync Callbacks
      • Updating Balances
      • QuickSync
    • Transactions
      • Shielding
        • Shield ERC-20 tokens
        • Shield base token
        • Shield NFTs
      • Private Transfers
        • Private ERC-20 Transfers
        • Private NFT Transfers
      • Cross-Contract Calls
      • Unshielding
        • Unshield ERC-20 tokens
        • Unshield base token
        • Unshield NFTs
      • UX: Private Transactions
    • Broadcasters
  • Cookbook SDK
    • Cookbook Overview
    • Recipe Guide: Write a zkApp
      • "Step" — A smart contract call
      • "Recipe" — Steps in series
      • "Combo Meal" — 2+ Recipes
    • Use your zkApp privately
  • Engine SDK
    • Engine Overview
  • ZK Account Abstraction
    • Account Abstraction Overview
    • Getting started with the contracts
    • Wallets
    • State Structure
    • Example Primitives
Powered by GitBook
On this page
  • Gas Estimate
  • Populate Transaction
  1. Wallet SDK
  2. Transactions
  3. Shielding

Shield ERC-20 tokens

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

Gas Estimate

import {
  RailgunERC20AmountRecipient,
  NetworkName
} from '@railgun-community/shared-models';
import {
  gasEstimateForShield,
  getShieldPrivateKeySignatureMessage,
} from '@railgun-community/wallet';
import { keccak256, Wallet } from 'ethers';

// Formatted token amounts and recipients.
const erc20AmountRecipients: RailgunERC20AmountRecipient[] = [
  {
    tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    amount: BigInt('0x10'), // hexadecimal amount
    recipientAddress: '0zk123...456', // RAILGUN address
  },
  {
    tokenAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
    amount: BigInt('0x20'), // hexadecimal amount
    recipientAddress: '0zk987...654', // RAILGUN address
  },
];

// The shieldPrivateKey enables the sender to decrypt 
// the receiver's address in the future.
const pKey = ...; // Private key of public wallet we are shielding from
const wallet = new Wallet(pKey);
const shieldSignatureMessage = getShieldPrivateKeySignatureMessage();
const shieldPrivateKey = keccak256(
  await wallet.signMessage(shieldSignatureMessage),
);

// Address of public wallet we are shielding from
const fromWalletAddress = '0xab5801a7d398351b8be11c439e05c5b3259aec9b';

const { gasEstimate } = await gasEstimateForShield(
  NetworkName.Ethereum,
  shieldPrivateKey,
  erc20AmountRecipients,  
  [], // nftAmountRecipients
  fromWalletAddress,
);

Populate Transaction

import {
  ...
  EVMGasType,
  TransactionGasDetails,
  getEVMGasTypeForTransaction
} from '@railgun-community/shared-models';
import {
  ...
  populateShield,
} from '@railgun-community/wallet';

...

const sendWithPublicWallet = true; // Always true for Shield transactions
const evmGasType: EVMGasType = getEVMGasTypeForTransaction(
  NetworkName.Ethereum,
  sendWithPublicWallet
);
const gasEstimate = ...; // Output from gasEstimateForShield in above example

let gasDetails: TransactionGasDetails;
switch (evmGasType) {
  case EVMGasType.Type0:
  case EVMGasType.Type1:
    gasDetails = {
      evmGasType,
      gasEstimate,
      gasPrice: BigInt('0x100000'), // Proper calculation of network gasPrice is not covered in this guide
    }
    break;
  case EVMGasType.Type2:
    // Proper calculation of gas Max Fee and gas Max Priority Fee is not covered in this guide. See: https://docs.alchemy.com/docs/how-to-build-a-gas-fee-estimator-using-eip-1559
    const maxFeePerGas: BigInt('0x100000');
    const maxPriorityFeePerGas: BigInt('0x010000');

    gasDetails = {
      evmGasType,
      gasEstimate,
      maxFeePerGas,
      maxPriorityFeePerGas,
    }
    break;
}

const { transaction } = await populateShield(
  NetworkName.Ethereum,
  shieldPrivateKey,
  erc20AmountRecipients,  
  [], // nftAmountRecipients
  gasDetails,
);

// Public wallet to shield from.
transaction.from = '0xab5...c9b';

// Send transaction. e.g. const wallet = new Wallet(pKey, provider); wallet.sendTransaction(transaction); from ethers.js
PreviousShieldingNextShield base token

Last updated 10 months ago