From c185961a624cd1d7e139c63d1600fd2ae17b76f4 Mon Sep 17 00:00:00 2001 From: Ayanami Date: Sun, 27 Feb 2022 07:32:39 +0900 Subject: [PATCH] Add --onlyrpc mode + Add mode to disable remote ip connection and to disable thegraph api + Faster event sync for deposit + Update README guide for users --- README.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++----- cli.js | 62 +++++++++++++++++++++++++++++++++---------- 2 files changed, 120 insertions(+), 21 deletions(-) mode change 100644 => 100755 cli.js diff --git a/README.md b/README.md index 7094498..b6e8872 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ Download and install [node.js](https://nodejs.org/en/download/). You also need to install C++ build tools in order to do 'npm install', for more information please checkout https://github.com/nodejs/node-gyp#on-unix. -For Windows: https://stackoverflow.com/a/64224475 +- For Windows: https://stackoverflow.com/a/64224475 -For MacOS: Install XCode Command Line Tools +- For MacOS: Install XCode Command Line Tools -For Linux: Install make & gcc, for ubuntu `$ sudo apt-get install -y build-essentials` +- For Linux: Install make & gcc, for ubuntu `$ sudo apt-get install -y build-essentials` If you have git installed on your system, clone the master branch. @@ -33,14 +33,26 @@ $ cd tornado-cli $ npm install ``` -If you want to use Tor connection to conceal ip address, install [Tor Browser](https://www.torproject.org/download/) and add `--tor 9150` for `cli.js` if you connect tor with browser. +If you want to use Tor connection to conceal ip address, install [Tor Browser](https://www.torproject.org/download/) and add `--tor 9150` for `cli.js` if you connect tor with browser. (For non tor-browser tor service you can use the default 9050 port). + 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 ` behind the command. -Example: +#### To deposit: + +```bash +$ node cli.js deposit --rpc --tor +``` + +Note that `--tor ` is optional. + +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 @@ -52,6 +64,22 @@ Tornado ETH balance is 9 Sender account ETH balance is 1004873.361652048361352542 ``` +#### To withdraw: + +```bash +$ node cli.js withdraw --rpc --relayer --tor +``` + +Note that `--relayer `, `--tor ` is optional. + +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 `=`. + +##### 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 @@ -70,7 +98,15 @@ One of the main features of tornado-cli is that it supports creating deposit not After the private-key like notes are backed up somewhere safe, you can copy the created deposit invoices and use them to create new deposit transaction on online environment. -To create deposit notes with `createNote` command. +#### To create deposit notes with `createNote` command. + +```bash +$ node cli.js createNote +``` + +To find out chainId value for your network, refer to https://chainlist.org/. + +##### Example: ```bash $ node cli.js createNote ETH 0.1 5 @@ -80,7 +116,15 @@ Backed up deposit note as ./backup-tornado-eth-0.1-5-0x1d9771a7.txt Backed up invoice as ./backup-tornadoInvoice-eth-0.1-5-0x1b680c7d.txt ``` -To create corresponding deposit transaction you only need invoice value, so that the deposit note could be stored without exposed anywhere. +#### To create corresponding deposit transaction with `depositInvoice` command. + +Creating deposit transaction with `depositInvoice` only requires valid deposit note created by `createNote` command, so that the deposit note could be stored without exposed anywhere. + +```bash +$ node cli.js depositInvoice +``` + +##### Example: ```bash node cli.js depositInvoice tornadoInvoice-eth-0.1-5-0x1b680c7dda0c2dd1b85f0fe126d49b16ed594b3cd6d5114db5f4593877a6b84f --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --tor 9150 @@ -97,6 +141,27 @@ 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 +``` + +##### 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) diff --git a/cli.js b/cli.js old mode 100644 new mode 100755 index 164c484..d41e36d --- a/cli.js +++ b/cli.js @@ -65,7 +65,7 @@ async function printERC20Balance({ address, name, tokenAddress }) { let tokenDecimals, tokenBalance, tokenName, tokenSymbol; const erc20ContractJson = require('./build/contracts/ERC20Mock.json'); erc20 = tokenAddress ? new web3.eth.Contract(erc20ContractJson.abi, tokenAddress) : erc20; - if (!isTestRPC || !multiCall) { + if (!isTestRPC && !multiCall) { const tokenCall = await useMultiCall([[tokenAddress, erc20.methods.balanceOf(address).encodeABI()], [tokenAddress, erc20.methods.decimals().encodeABI()], [tokenAddress, erc20.methods.name().encodeABI()], [tokenAddress, erc20.methods.symbol().encodeABI()]]); tokenDecimals = parseInt(tokenCall[1]); tokenBalance = new BigNumber(tokenCall[0]).div(BigNumber(10).pow(tokenDecimals)); @@ -220,7 +220,7 @@ async function createInvoice({ currency, amount, chainId }) { */ async function deposit({ currency, amount, commitmentNote }) { assert(senderAccount != null, 'Error! PRIVATE_KEY not found. Please provide PRIVATE_KEY in .env file if you deposit'); - let commitment; + let commitment, noteString; if (!commitmentNote) { console.log("Creating new random deposit note"); const deposit = createDeposit({ @@ -228,7 +228,7 @@ async function deposit({ currency, amount, commitmentNote }) { secret: rbigint(31) }); const note = toHex(deposit.preimage, 62); - const noteString = `tornado-${currency}-${amount}-${netId}-${note}`; + noteString = `tornado-${currency}-${amount}-${netId}-${note}`; console.log(`Your note: ${noteString}`); await backupNote({ currency, amount, netId, note, noteString }); commitment = toHex(deposit.commitment); @@ -300,7 +300,7 @@ async function generateMerkleProof(deposit, currency, amount) { // Validate that our data is correct const root = tree.root(); let isValidRoot, isSpent; - if (!isTestRPC || !multiCall) { + if (!isTestRPC && !multiCall) { const callContract = await useMultiCall([[tornadoContract._address, tornadoContract.methods.isKnownRoot(toHex(root)).encodeABI()], [tornadoContract._address, tornadoContract.methods.isSpent(toHex(deposit.nullifierHash)).encodeABI()]]) isValidRoot = web3.eth.abi.decodeParameter('bool', callContract[0]); isSpent = web3.eth.abi.decodeParameter('bool', callContract[1]); @@ -459,7 +459,7 @@ async function send({ address, amount, tokenAddress }) { const erc20ContractJson = require('./build/contracts/ERC20Mock.json'); erc20 = new web3.eth.Contract(erc20ContractJson.abi, tokenAddress); let tokenBalance, tokenDecimals, tokenSymbol; - if (!isTestRPC || !multiCall) { + if (!isTestRPC && !multiCall) { const callToken = await useMultiCall([[tokenAddress, erc20.methods.balanceOf(senderAccount).encodeABI()], [tokenAddress, erc20.methods.decimals().encodeABI()], [tokenAddress, erc20.methods.symbol().encodeABI()]]); tokenBalance = new BigNumber(callToken[0]); tokenDecimals = parseInt(callToken[1]); @@ -1036,12 +1036,20 @@ async function fetchEvents({ type, currency, amount }) { if (Object.keys(result).length === 0) { i = latestTimestamp; } else { - const resultBlock = result[result.length - 1].blockNumber; - const getResultBlock = await web3.eth.getBlock(resultBlock); - const resultTimestamp = getResultBlock.timestamp; - await updateCache(result); - i = resultTimestamp; - console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock)); + if (type === "deposit") { + const resultBlock = result[result.length - 1].blockNumber; + const resultTimestamp = result[result.length - 1].timestamp; + await updateCache(result); + i = resultTimestamp; + console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock)); + } else { + const resultBlock = result[result.length - 1].blockNumber; + const getResultBlock = await web3.eth.getBlock(resultBlock); + const resultTimestamp = getResultBlock.timestamp; + await updateCache(result); + i = resultTimestamp; + console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock)); + } } } } else { @@ -1051,7 +1059,7 @@ async function fetchEvents({ type, currency, amount }) { } await fetchGraphEvents(); } - if (!privateRpc || !subgraph || !isTestRPC) { + if (!privateRpc && !subgraph && !isTestRPC) { await syncGraphEvents(); } else { await syncEvents(); @@ -1217,7 +1225,7 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceC } const rpcHost = new URL(rpc).hostname; const isIpPrivate = is_ip_private(rpcHost); - if (!isIpPrivate && !rpc.includes("localhost")) { + if (!isIpPrivate && !rpc.includes("localhost") && !privateRpc) { try { const fetchRemoteIP = await axios.get('https://ip.tornado.cash', ipOptions); const { country, ip } = fetchRemoteIP.data; @@ -1322,7 +1330,8 @@ async function main() { .option('-r, --rpc ', 'The RPC that CLI should interact with', 'http://localhost:8545') .option('-R, --relayer ', 'Withdraw via relayer') .option('-T, --tor ', 'Optional tor port') - .option('-L, --local', 'Local Node - Does not submit signed transaction to the node'); + .option('-L, --local', 'Local Node - Does not submit signed transaction to the node') + .option('-o, --onlyrpc', 'Only rpc mode - Does not enable thegraph api nor remote ip detection'); program .command('createNote ') .description( @@ -1338,6 +1347,9 @@ async function main() { 'Submit a deposit of invoice from default eth account and return the resulting note.' ) .action(async (invoice) => { + if (program.onlyrpc) { + privateRpc = true; + } torPort = program.tor; const { currency, amount, netId, commitmentNote } = parseInvoice(invoice); await init({ rpc: program.rpc, currency, amount, localMode: program.local }); @@ -1350,6 +1362,9 @@ async function main() { 'Submit a deposit of specified currency and amount from default eth account and return the resulting note. The currency is one of (ETH|DAI|cDAI|USDC|cUSDC|USDT). The amount depends on currency, see config.js file or visit https://tornado.cash.' ) .action(async (currency, amount) => { + if (program.onlyrpc) { + privateRpc = true; + } currency = currency.toLowerCase(); torPort = program.tor; await init({ rpc: program.rpc, currency, amount, localMode: program.local }); @@ -1361,6 +1376,9 @@ async function main() { 'Withdraw a note to a recipient account using relayer or specified private key. You can exchange some of your deposit`s tokens to ETH during the withdrawal by specifing ETH_purchase (e.g. 0.01) to pay for gas in future transactions. Also see the --relayer option.' ) .action(async (noteString, recipient, refund) => { + if (program.onlyrpc) { + privateRpc = true; + } const { currency, amount, netId, deposit } = parseNote(noteString); torPort = program.tor; await init({ rpc: program.rpc, noteNetId: netId, currency, amount, localMode: program.local }); @@ -1377,6 +1395,9 @@ async function main() { .command('balance [address] [token_address]') .description('Check ETH and ERC20 balance') .action(async (address, tokenAddress) => { + if (program.onlyrpc) { + privateRpc = true; + } torPort = program.tor; await init({ rpc: program.rpc, balanceCheck: true }); if (!address && senderAccount) { @@ -1392,6 +1413,9 @@ async function main() { .command('send
[amount] [token_address]') .description('Send ETH or ERC to address') .action(async (address, amount, tokenAddress) => { + if (program.onlyrpc) { + privateRpc = true; + } torPort = program.tor; await init({ rpc: program.rpc, balanceCheck: true, localMode: program.local }); await send({ address, amount, tokenAddress }); @@ -1400,6 +1424,9 @@ async function main() { .command('broadcast ') .description('Submit signed TX to the remote node') .action(async (signedTX) => { + if (program.onlyrpc) { + privateRpc = true; + } torPort = program.tor; await init({ rpc: program.rpc, balanceCheck: true }); await submitTransaction(signedTX); @@ -1410,6 +1437,9 @@ async function main() { 'Shows the deposit and withdrawal of the provided note. This might be necessary to show the origin of assets held in your withdrawal address.' ) .action(async (noteString) => { + if (program.onlyrpc) { + privateRpc = true; + } const { currency, amount, netId, deposit } = parseNote(noteString); torPort = program.tor; await init({ rpc: program.rpc, noteNetId: netId, currency, amount }); @@ -1445,6 +1475,9 @@ async function main() { 'Sync the local cache file of deposit / withdrawal events for specific currency.' ) .action(async (type, currency, amount) => { + if (program.onlyrpc) { + privateRpc = true; + } console.log("Starting event sync command"); currency = currency.toLowerCase(); torPort = program.tor; @@ -1456,6 +1489,7 @@ async function main() { .command('test') .description('Perform an automated test. It deposits and withdraws one ETH and one ERC20 note. Uses ganache.') .action(async () => { + privateRpc = true; console.log('Start performing ETH deposit-withdraw test'); let currency = 'eth'; let amount = '0.1';