8 minute read

The Instructions for Tornado Cash Deposit and Withdrawal via CLI


Declaration

  • Tornado Cash was sanctioned by the U.S. Treasury on 08/08/2022,
    making it illegal for U.S. citizens to interact with the core and governance contracts.

  • This blog is for Research Purposes ONLY.

  • ALL CRIMES WILL BE BROUGHT TO JUSTICE.


System Information

Intel x86-64 + Ubuntu 22.04.4 LTS + Linux 6.5.0-25-generic


Step 1 - Node.js Installation

  1. Install Node.js using Package Manager:

     curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
     nvm install 14
    

    Note that the Tornado Cash CLI used in this blog only supports v14.21.3

  2. Optional - If you have multiple versions of Node.js:

    nvm use 14
    

    which displays Now using node v14.21.3 (npm v6.14.18)

  3. Check Node.js and NPM versions after Node.js installation completes:

    node --version
    

    which should be v14.21.3

    npm --version
    

    which currently is 6.14.18


Step 2 - Tornado Cash CLI Installation (Build from Source)

Ref-1: GitHub-Official-Repository (public archive after the OFAC sanctions)

Ref-2: Community-Repository & Docs (please pay attention to any difference from the official one)

  1. Dependencies:

     sudo apt-get update
     sudo apt-get install build-essential
    
  2. Build Tornado Cash CLI:

    Optional-1-Official Version:

     git clone https://github.com/tornadocash/tornado-cli.git
     mv tornado-cli tornado-cash-cli-official
     cd tornado-cash-cli-official
    
     npm install
    

    Optional-2-Community Version:

     git clone https://github.com/tornadocash/tornado-cli.git
     mv tornado-cli tornado-cash-cli-community
     cd tornado-cash-cli-community
    
     npm install 
    

    Note that the official version has issues with the function fetchGasPrice() in the file cli.js (Line 702) due to the lack of necessary maintenance. If you do not trust Tornado Cash Community, please fix all possible issues by yourself.

    All the following steps are run on the community version but should also work with the official version.


Step 3 - Deposit ETH into Tornado Cash

Use the following command:

node cli.js deposit <currency> <amount> \ 
--rpc <rpc-url> --tor <tor-port> --private-key <private-key> --gas-speed <gas-speed>
  • Parameter <currency>: set it to ETH for depositing ETH

  • Parameter <amount>: select from [ 0.1, 1, 10, 100 ] when depositing ETH

  • Parameter <rpc-url>: set it to the URL of RPC provider

    which can be selected from RPC Server Address under Ethereum on ChainList

    Please choose the ones that ensure privacy since many RPC providers (i.e., Infura & Alchemy) censor Tornado Cash.

    Highly recommend to use Ethereum Archive Node built by yourself as the RPC provider: http://localhost:8545

  • Parameter <tor-port>: set it to 9150 when using Tor Browser, or 9050 when using Tor standalone

    Highly recommend to use Tor Project when you are using a public RPC provider to hide your IP Address

  • Parameter <private-key>: set it to the private key of Ethereum Account who sends deposit transaction (Pay Tx Fee)

  • Parameter gas-speed: select from [ instant, fast, standard, low ]

A successful deposit process looks like this:

Connecting to remote node
Local RPC detected
Creating new random deposit note
Your note: <your-deposit-note>
Backed up deposit note as ./backup-<your-deposit-note>.txt
Tornado contract balance is XXX1 ETH
Sender account balance is YYY1 ETH
Submitting deposit transaction
Gas price:  AAAA
Gas limit:  BBBB
Transaction fee:  CCCC ETH
Transaction cost:  DDDD ETH
Confirm the transaction [Y/n] Y
Submitting transaction to the remote node
View transaction on block explorer https://etherscan.io/tx/<your-deposit-transaction>
Tornado contract balance is XXX2 ETH
Sender account balance is YYY2 ETH

Step 4 - Withdraw ETH from Tornado Cash

If you DO use Tornado Cash Relayer

Use the following command:

node cli.js withdraw <deposit-note> <recipient> \
--rpc <rpc-url> --tor <tor-port> --relayer <relayer-url>  --gas-speed <gas-speed>

For the first withdrawal to new ethereum account without ETH Balance

  • Parameter <deposit-note>: set it to the deposit note generated by the deposit process (not the backup file)

  • Parameter <recipient>: set it to the public key (address) of Ethereum Account who receives the ETH

  • Parameter <rpc-url>: set it to the URL of RPC provider

    which can be selected from RPC Server Address under Ethereum on ChainList

    Please choose the ones that ensure privacy since many RPC providers (i.e., Infura & Alchemy) censor Tornado Cash.

    Highly recommend to use Ethereum Archive Node built by yourself as the RPC provider: http://localhost:8545

  • Parameter <tor-port>: set it to 9150 when using Tor Browser, or 9050 when using Tor standalone

    Highly recommend to use Tor Project when you are using a public RPC provider to hide your IP Address

  • Parameter <relayer-url>: set it to the URL of Tornado Cash Relayer on Ethereum (Pay Tx Fee).

  • Parameter gas-speed: select from [ instant, fast, standard, low ]

    Here are some active relayers (unverified):

    Relayer-URL ENS Name Address Service Fee
    https://black-hardy.com/ k-relayer.eth 0xC494…e35c     0.43%
    https://eth.t-relayer.com/ t-relayer.eth 0x0000…74fe     0.43%
    https://torn.relayersdao.finance/ relayer007.eth 0xa010…f012     0.39%
    https://eth.reltor.su/ reltor.eth 0x4750…29C5     0.42%

A successful withdrawal process using a relayer looks like this:

Connecting to remote node
Local RPC detected
Relay address: <relayer-address>
Loaded cached XXX ETH deposit events for BBB1 block
Fetching XXX ETH deposit events for Ethereum network
Querying latest events from RPC
...
Fetched XXX ETH deposit events to block: BBB2
Added XXX ETH deposit zero event to block: BBB2
Cache updated for Tornado deposit XXX eth instance to block BBB2 successfully
Total deposits: DDDDD
Computing deposit events merkle tree and its root
Generating SNARK proof
Proof time: TTT1s
Generating SNARK proof
Proof time: TTT2s
Sending withdraw transaction through relay
Relayer fee:  FFF1 ETH
Total fees:  FFF2 ETH
Amount to receive:  ZZZ1 ETH 
Confirm the transaction [Y/n] Y
Current job status ACCEPTED, confirmations: undefined
Current job status SENT, confirmations: undefined
Current job status MINED, confirmations: 0
...
Current job status MINED, confirmations: N
Current job status CONFIRMED, confirmations: N+1
Transaction submitted through the relay. 
View transaction on block explorer https://etherscan.io/tx/<your-withdrawal-transaction>
Transaction mined in block BBB3
STATUS CONFIRMED
Recipient balance is ZZZ2 ETH
Done withdrawal from Tornado Cash

If you DO NOT use Tornado Cash Relayer

Use the following command:

node cli.js withdraw <deposit-note> <recipient> \
--rpc <rpc-url> --tor <tor-port> --private-key <private-key>  --gas-speed <gas-speed>

Warning: This will link the recipient and the sender of withdrawal transaction

  • Parameter <deposit-note>: set it to the deposit note generated by the deposit process (not the backup file)

  • Parameter <recipient>: set it to the public key (address) of Ethereum Account who receives the ETH

  • Parameter <rpc-url>: set it to the URL of RPC provider

    which can be selected from RPC Server Address under Ethereum on ChainList

    Please choose the ones that ensure privacy since many RPC providers (i.e., Infura & Alchemy) censor Tornado Cash.

    Highly recommend to use Ethereum Archive Node built by yourself as the RPC provider: http://localhost:8545

  • Parameter <tor-port>: set it to 9150 when using Tor Browser, or 9050 when using Tor standalone

    Highly recommend to use Tor Project when you are using a public RPC provider to hide your IP Address

  • Parameter <private-key>: set it to the private key of Ethereum Account who sends withdrawal transaction (Pay Tx Fee)

  • Parameter gas-speed: select from [ instant, fast, standard, low ]


Miscellaneous

  • It needs more modifications and configurations if you want to access your own Ethereum Archive Node when using Tor.
    It is obvious since you cannot visit localhost directly when you are inside the Tor network.

  • Parameter gas-speed seems not to work. Please ignore it and choose a low gas price (can be generated automatically or filled manually based on Ethereum Gas Tracker/Time-based Gas Price Strategy) to deposit and withdraw.

    Here is an example of setting the gas price manually to 3.3 gwei in cli.js (Line 170-172):

      const { _, gasLimit } = await feeOracle.getGasParams({ tx: incompletedTx, txType });
      const gasPrice = '0x00C4B20100';  // 3300000000
      const gasCosts = toBN(gasPrice).mul(toBN(gasLimit));
    
  • There is a website https://ipfs.io/ipns/tornadocash.eth deployed on IPFS by Tornado Cash Community (unsure safety)

  • Plan to check the difference between community versions (v1 + v2) and the official version (public archive)

  • Be aware of any suspected phishing attempts (which could steal your money and identity)
    Even if they are Tornado Cash Community, Tornado Cash Relayer, and THIS BLOG!!!

    Here is the latest report of Tornado Cash Backend Exploit.