Compare commits
3 Commits
b7929bd16c
...
f000d0af36
Author | SHA1 | Date | |
---|---|---|---|
f000d0af36 | |||
910643ab5e | |||
e9fcc51dae |
121
README.md
121
README.md
@ -1,6 +1,6 @@
|
||||
# Tornado-CLI
|
||||
|
||||
Command line tool to interact with [Tornado Cash](https://tornadocashcommunity.eth.link).
|
||||
Command line tool to interact with [Tornado Cash](https://tornado.ws).
|
||||
|
||||
### Warning!
|
||||
Current cli version doesn't support [Anonymity Mining](https://tornado-cash.medium.com/tornado-cash-governance-proposal-a55c5c7d0703)
|
||||
@ -19,12 +19,10 @@ You also need to install C++ build tools in order to do 'npm install', for more
|
||||
If you have git installed on your system, clone the master branch.
|
||||
|
||||
```bash
|
||||
$ git clone https://development.tornadocash.community/tornadocash/tornado-cli
|
||||
$ git clone https://git.tornado.ws/tornadocash/tornado-cli
|
||||
```
|
||||
|
||||
Or, download the archive file from github
|
||||
|
||||
https://development.tornadocash.community/tornadocash/tornado-cli/archive/refs/heads/master.zip
|
||||
Or, download the archive file from git: https://git.tornado.ws/tornadocash/tornado-cli/archive/master.zip
|
||||
|
||||
After downloading or cloning the repository, you must install necessary libraries using the following command.
|
||||
|
||||
@ -38,23 +36,23 @@ If you want to use Tor connection to conceal ip address, install [Tor Browser](h
|
||||
Note that you should reset your tor connection by restarting the browser every time when you deposit & withdraw otherwise you will have the same exit node used for connection.
|
||||
|
||||
### Goerli, Mainnet, Binance Smart Chain, Gnosis Chain, Polygon Network, Arbitrum, Avalanche
|
||||
1. Add `PRIVATE_KEY` to `.env` file
|
||||
2. `node cli.js --help`
|
||||
3. If you want to use secure, anonymous tor connection add `--tor <torPort>` behind the command.
|
||||
1. `node cli.js --help`
|
||||
2. If you want to use secure, anonymous tor connection add `--tor <torPort>` behind the command.
|
||||
3. Add `PRIVATE_KEY` to `.env` file (optional, only if you want to use it for many operations) - open `.env.example` file, add private key after `PRIVATE_KEY=` and rename file to `.env`.
|
||||
|
||||
#### To deposit:
|
||||
|
||||
```bash
|
||||
$ node cli.js deposit <currency> <amount> --rpc <rpc url> --tor <torPort>
|
||||
$ node cli.js deposit <currency> <amount> --rpc <rpc url> --tor <torPort> --private-key <private key>
|
||||
```
|
||||
|
||||
Note that `--tor <torPort>` is optional.
|
||||
Note that `--tor <torPort>` is optional, and use `--private-key <private key>` only if you didn't add it to `.env` file.
|
||||
|
||||
For RPC nodes please refer to the list of public RPC nodes below.
|
||||
|
||||
##### Example:
|
||||
```bash
|
||||
$ node cli.js deposit ETH 0.1 --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --tor 9150
|
||||
$ node cli.js deposit ETH 0.1 --rpc https://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607 --tor 9150
|
||||
|
||||
Your note: tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652
|
||||
Tornado ETH balance is 8.9
|
||||
@ -67,21 +65,19 @@ Sender account ETH balance is 1004873.361652048361352542
|
||||
#### To withdraw:
|
||||
|
||||
```bash
|
||||
$ node cli.js withdraw <note> <recipient> --rpc <rpc url> --relayer <relayer url> --tor <torPort>
|
||||
$ node cli.js withdraw <note> <recipient> --rpc <rpc url> --relayer <relayer url> --tor <torPort> --private-key <private key>
|
||||
```
|
||||
|
||||
Note that `--relayer <relayer url>`, `--tor <torPort>` is optional.
|
||||
Note that `--relayer <relayer url>`, `--tor <torPort>` is optional, and use `--private-key <private key>` only if you withdraw without relayer.
|
||||
|
||||
If you want to use Tornado Cash relayer for your first withdrawal to your new ethereum account, please refer to the list of relayers below.
|
||||
|
||||
If you don't need relayer while doing withdrawals, you must apply your withdrawal account's private key to `.env` file.
|
||||
|
||||
Copy the `PRIVATE_KEY=` line of `.env.example` to `.env`, and add your private key behind the `=`.
|
||||
If you don't need relayer while doing withdrawals, you must provide your withdrawal account's private key - either as parameter, or by adding it to `.env` file.
|
||||
|
||||
##### Example:
|
||||
|
||||
```bash
|
||||
$ node cli.js withdraw tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 0x8589427373D6D84E98730D7795D8f6f8731FDA16 --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --relayer https://goerli-frelay.duckdns.org --tor 9150
|
||||
$ node cli.js withdraw tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 0x8589427373D6D84E98730D7795D8f6f8731FDA16 --rpc https://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607 --relayer https://goerli-relay.example.org --tor 9150
|
||||
|
||||
Relay address: 0x6A31736e7490AbE5D5676be059DFf064AB4aC754
|
||||
Getting current state from tornado contract
|
||||
@ -141,42 +137,19 @@ Tornado contract balance is xxx.x ETH
|
||||
Sender account balance is x.xxxxxxx ETH
|
||||
```
|
||||
|
||||
#### To withdraw, you will need deposit note that matches with your deposit transaction.
|
||||
|
||||
```bash
|
||||
$ node cli.js withdraw <note> <recipient>
|
||||
```
|
||||
|
||||
##### Example:
|
||||
|
||||
```bash
|
||||
$ node cli.js withdraw tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 0x8589427373D6D84E98730D7795D8f6f8731FDA16 --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --relayer https://goerli-frelay.duckdns.org --tor 9150
|
||||
|
||||
Relay address: 0x6A31736e7490AbE5D5676be059DFf064AB4aC754
|
||||
Getting current state from tornado contract
|
||||
Generating SNARK proof
|
||||
Proof time: 9117.051ms
|
||||
Sending withdraw transaction through relay
|
||||
Transaction submitted through the relay. View transaction on etherscan https://goerli.etherscan.io/tx/0xcb21ae8cad723818c6bc7273e83e00c8393fcdbe74802ce5d562acad691a2a7b
|
||||
Transaction mined in block 17036120
|
||||
Done
|
||||
```
|
||||
|
||||
### List of public rpc & relayers for withdrawal
|
||||
|
||||
Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
### List of rpc & relayers for withdrawal
|
||||
|
||||
```json
|
||||
{
|
||||
"netId1":{
|
||||
"rpcUrls":{
|
||||
"publicRpc1":{
|
||||
"name":"SecureRPC",
|
||||
"url":"https://api.securerpc.com/v1"
|
||||
"name":"1RPC",
|
||||
"url":"https://1rpc.io/eth"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name":"CloudFlare",
|
||||
"url":"https://cloudflare-eth.com"
|
||||
"Chainnodes":{
|
||||
"name": "Chainnodes",
|
||||
"url": "https://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607"
|
||||
}
|
||||
},
|
||||
"relayers": {
|
||||
@ -276,7 +249,7 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
"rpcUrls":{
|
||||
"publicRpc1":{
|
||||
"name":"BSC Public RPC 1",
|
||||
"url":"https://bsc-dataseed.binance.org"
|
||||
"url":"https://1rpc.io/bnb"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name":"BSC Public RPC 2",
|
||||
@ -365,7 +338,7 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
"publicRpc":{
|
||||
"name":"Gnosis Chain RPC",
|
||||
"url":"https://rpc.gnosischain.com"
|
||||
},
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"torndao.eth": {
|
||||
@ -378,20 +351,12 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
"netId137":{
|
||||
"rpcUrls":{
|
||||
"publicRpc1":{
|
||||
"name":"publicRpc1",
|
||||
"url":"https://rpc-mainnet.maticvigil.com"
|
||||
"name":"1RPC",
|
||||
"url":"https://1rpc.io/matic"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name":"publicRpc2",
|
||||
"url":"https://rpc-mainnet.matic.network"
|
||||
},
|
||||
"publicRpc3":{
|
||||
"name":"publicRpc3",
|
||||
"url":"https://matic-mainnet.chainstacklabs.com"
|
||||
},
|
||||
"MyEtherWallet":{
|
||||
"name":"MyEtherWallet",
|
||||
"url":"https://nodes.mewapi.io/ws/matic"
|
||||
"Chainnodes":{
|
||||
"name": "Chainnodes",
|
||||
"url": "https://polygon-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607"
|
||||
}
|
||||
},
|
||||
"relayers": {
|
||||
@ -442,6 +407,10 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
"publicRpc1":{
|
||||
"name":"Arbitrum Public RPC",
|
||||
"url":"https://arb1.arbitrum.io/rpc"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name": "ChainnodesRPC",
|
||||
"url": "https://arbitrum-one.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
@ -460,8 +429,8 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
"netId43114":{
|
||||
"rpcUrls":{
|
||||
"publicRpc":{
|
||||
"name":"Avalanche RPC",
|
||||
"url":"https://api.avax.network/ext/bc/C/rpc"
|
||||
"name":"1RPC",
|
||||
"url":"https://1rpc.io/avax/c"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
@ -489,9 +458,13 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
},
|
||||
"netId10":{
|
||||
"rpcUrls":{
|
||||
"Optimism":{
|
||||
"name":"Optimism Public RPC",
|
||||
"url":"https://mainnet.optimism.io"
|
||||
"publicRpc1":{
|
||||
"name":"1RPC",
|
||||
"url":"https://1rpc.io/op"
|
||||
},
|
||||
"Chainnodes":{
|
||||
"name": "Chainnodes",
|
||||
"url": "https://optimism-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
@ -504,18 +477,10 @@ Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
},
|
||||
"netId5":{
|
||||
"rpcUrls":{
|
||||
"publicRpc1":{
|
||||
"name":"Infura",
|
||||
"url":"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"
|
||||
},
|
||||
"Slockit":{
|
||||
"name":"Slockit",
|
||||
"url":"https://rpc.slock.it/goerli"
|
||||
},
|
||||
"Prylabs":{
|
||||
"name":"Prylabs",
|
||||
"url":"https://goerli.prylabs.net"
|
||||
},
|
||||
"Chainnodes":{
|
||||
"name":"Chainnodes RPC",
|
||||
"url":"https://goerli.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607"
|
||||
}
|
||||
},
|
||||
"relayers":{}
|
||||
}
|
||||
|
47
cli.js
47
cli.js
@ -373,25 +373,12 @@ async function deposit({ currency, amount, commitmentNote }) {
|
||||
* @param deposit Deposit object
|
||||
*/
|
||||
async function generateMerkleProof(deposit, currency, amount) {
|
||||
let leafIndex = -1;
|
||||
// Get all deposit events from smart contract and assemble merkle tree from them
|
||||
|
||||
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount });
|
||||
const { tree, leaves, root } = computeDepositEventsTree(cachedEvents);
|
||||
|
||||
const leaves = cachedEvents
|
||||
.sort((a, b) => a.leafIndex - b.leafIndex) // Sort events in chronological order
|
||||
.map((e) => {
|
||||
const index = toBN(e.leafIndex).toNumber();
|
||||
|
||||
if (toBN(e.commitment).eq(toBN(deposit.commitmentHex))) {
|
||||
leafIndex = index;
|
||||
}
|
||||
return toBN(e.commitment).toString(10);
|
||||
});
|
||||
const tree = new merkleTree(MERKLE_TREE_HEIGHT, leaves);
|
||||
|
||||
// Validate that our data is correct
|
||||
const root = tree.root();
|
||||
// Validate that merkle tree is valid, deposit data is correct and note not spent.
|
||||
const leafIndex = leaves.findIndex((commitment) => toBN(deposit.commitmentHex).toString(10) === commitment);
|
||||
let isValidRoot, isSpent;
|
||||
if (!isTestRPC && !multiCall) {
|
||||
const callContract = await useMultiCall([
|
||||
@ -1381,7 +1368,7 @@ async function promptConfirmation() {
|
||||
/**
|
||||
* Init web3, contracts, and snark
|
||||
*/
|
||||
async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceCheck, localMode }) {
|
||||
async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceCheck, localMode, privateKey }) {
|
||||
let contractJson, instanceJson, erc20ContractJson, erc20tornadoJson, tornadoAddress, tokenAddress;
|
||||
let ipOptions = {};
|
||||
|
||||
@ -1441,13 +1428,13 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceC
|
||||
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20;
|
||||
ETH_AMOUNT = process.env.ETH_AMOUNT;
|
||||
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT;
|
||||
const privKey = process.env.PRIVATE_KEY;
|
||||
const privKey = privateKey || process.env.PRIVATE_KEY;
|
||||
|
||||
if (privKey) {
|
||||
if (privKey.includes('0x')) {
|
||||
PRIVATE_KEY = process.env.PRIVATE_KEY.substring(2);
|
||||
if (privKey.startsWith('0x')) {
|
||||
PRIVATE_KEY = privKey.substring(2);
|
||||
} else {
|
||||
PRIVATE_KEY = process.env.PRIVATE_KEY;
|
||||
PRIVATE_KEY = privKey;
|
||||
}
|
||||
}
|
||||
if (PRIVATE_KEY) {
|
||||
@ -1515,6 +1502,7 @@ async function main() {
|
||||
.option('-r, --rpc <URL>', 'The RPC that CLI should interact with', 'http://localhost:8545')
|
||||
.option('-R, --relayer <URL>', 'Withdraw via relayer')
|
||||
.option('-T, --tor <PORT>', 'Optional tor port')
|
||||
.option('-p, --private-key <KEY>', "Wallet private key - If you didn't add it to .env file and it is needed for operation")
|
||||
.option('-S --gas_speed <SPEED>', 'Gas speed preference [ instant, fast, standard, low ]')
|
||||
.option('-N --noconfirmation', 'No confirmation mode - Does not query confirmation ')
|
||||
.option('-L, --local-rpc', 'Local node mode - Does not submit signed transaction to the node')
|
||||
@ -1535,7 +1523,7 @@ async function main() {
|
||||
statePreferences(program);
|
||||
|
||||
const { currency, amount, netId, commitmentNote } = parseInvoice(invoice);
|
||||
await init({ rpc: program.rpc, currency, amount, localMode: program.local });
|
||||
await init({ rpc: program.rpc, currency, amount, localMode: program.local, privateKey: program.privateKey });
|
||||
console.log('Creating', currency.toUpperCase(), amount, 'deposit for', netName, 'Tornado Cash Instance');
|
||||
await deposit({ currency, amount, commitmentNote });
|
||||
});
|
||||
@ -1549,7 +1537,7 @@ async function main() {
|
||||
|
||||
statePreferences(program);
|
||||
|
||||
await init({ rpc: program.rpc, currency, amount, localMode: program.local });
|
||||
await init({ rpc: program.rpc, currency, amount, localMode: program.local, privateKey: program.privateKey });
|
||||
await deposit({ currency, amount });
|
||||
});
|
||||
program
|
||||
@ -1562,7 +1550,14 @@ async function main() {
|
||||
|
||||
const { currency, amount, netId, deposit } = parseNote(noteString);
|
||||
|
||||
await init({ rpc: program.rpc, noteNetId: netId, currency, amount, localMode: program.local });
|
||||
await init({
|
||||
rpc: program.rpc,
|
||||
noteNetId: netId,
|
||||
currency,
|
||||
amount,
|
||||
localMode: program.local,
|
||||
privateKey: program.privateKey
|
||||
});
|
||||
await withdraw({
|
||||
deposit,
|
||||
currency,
|
||||
@ -1594,7 +1589,7 @@ async function main() {
|
||||
.action(async (address, amount, tokenAddress) => {
|
||||
statePreferences(program);
|
||||
|
||||
await init({ rpc: program.rpc, balanceCheck: true, localMode: program.local });
|
||||
await init({ rpc: program.rpc, balanceCheck: true, localMode: program.local, privateKey: program.privateKey });
|
||||
await send({ address, amount, tokenAddress });
|
||||
});
|
||||
program
|
||||
@ -1706,7 +1701,7 @@ async function main() {
|
||||
console.log('Start performing ETH deposit-withdraw test');
|
||||
let currency = 'eth';
|
||||
let amount = '0.1';
|
||||
await init({ rpc: program.rpc, currency, amount });
|
||||
await init({ rpc: program.rpc, currency, amount, privateKey: program.privateKey });
|
||||
let noteString = await deposit({ currency, amount });
|
||||
let parsedNote = parseNote(noteString);
|
||||
await withdraw({
|
||||
|
Loading…
Reference in New Issue
Block a user