diff --git a/README.md b/README.md index 216c3f7..59b77f7 100644 --- a/README.md +++ b/README.md @@ -53,20 +53,43 @@ Use browser version on Kovan: 1. `npx http-server` - serve current dir, you can use any other static http server 1. Open `localhost:8080` -Use with command line version with Ganache: -### ETHTornado -1. `npm run migrate:dev` -1. `./cli.js deposit` -1. `./cli.js withdraw ` -1. `./cli.js balance ` +Use with command line version. Works for Ganache, Kovan and Mainnet: +### Initialization +1. `cp .env.example .env` +1. `npm run download` +1. `npm run build:contract` -### ERC20Tornado +### Ganache +1. make sure you complete steps from Initialization +1. `ganache-cli -i 1337` 1. `npm run migrate:dev` -1. `./cli.js depositErc20` -1. `./cli.js withdrawErc20 ` -1. `./cli.js balanceErc20 ` +1. `./cli.js test` +1. `./cli.js --help` -If you want, you can point the app to existing tornado contracts on Mainnet or Kovan. It should work without any problems +### Kovan, Mainnet +1. make sure you complete steps from Initialization +1. Add `PRIVATE_KEY` to `.env` file +1. `./cli.js --help` + +Example: +```bash +./cli.js deposit ETH 0.1 --rpc https://kovan.infura.io/v3/27a9649f826b4e31a83e07ae09a87448 +Your note: tornado-eth-0.1-42-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 +Tornado ETH balance is 8.9 +Sender account ETH balance is 1004873.470619891361352542 +Submitting deposit transaction +Tornado ETH balance is 9 +Sender account ETH balance is 1004873.361652048361352542 + +./cli.js withdraw tornado-eth-0.1-42-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 0x8589427373D6D84E98730D7795D8f6f8731FDA16 --rpc https://kovan.infura.io/v3/27a9649f826b4e31a83e07ae09a87448 --relayer https://kovan-frelay.duckdns.orgRelay 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://kovan.etherscan.io/tx/0xcb21ae8cad723818c6bc7273e83e00c8393fcdbe74802ce5d562acad691a2a7b +Transaction mined in block 17036120 +Done +``` ## Deploy ETH Tornado Cash 1. `cp .env.example .env` diff --git a/cli.js b/cli.js index 1d582ed..838864a 100755 --- a/cli.js +++ b/cli.js @@ -1,6 +1,7 @@ -#!/usr/bin/env node +#!/usr/bin/env NODE_OPTIONS=--no-warnings node // Temporary demo client // Works both in browser and node.js + require('dotenv').config() const fs = require('fs') const axios = require('axios') @@ -367,13 +368,14 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) { if (inBrowser) { // Initialize using injected web3 (Metamask) // To assemble web version run `npm run browserify` - // web3 = new Web3(window.web3.currentProvider, null, { transactionConfirmationBlocks: 1 }) - // contractJson = await (await fetch('build/contracts/ETHTornado.json')).json() - // circuit = await (await fetch('build/circuits/withdraw.json')).json() - // proving_key = await (await fetch('build/circuits/withdraw_proving_key.bin')).arrayBuffer() - // MERKLE_TREE_HEIGHT = 16 - // ETH_AMOUNT = 1e18 - // TOKEN_AMOUNT = 1e19 + web3 = new Web3(window.web3.currentProvider, null, { transactionConfirmationBlocks: 1 }) + contractJson = await (await fetch('build/contracts/ETHTornado.json')).json() + circuit = await (await fetch('build/circuits/withdraw.json')).json() + proving_key = await (await fetch('build/circuits/withdraw_proving_key.bin')).arrayBuffer() + MERKLE_TREE_HEIGHT = 20 + ETH_AMOUNT = 1e18 + TOKEN_AMOUNT = 1e19 + senderAccount = (await web3.eth.getAccounts())[0] } else { // Initialize from local node web3 = new Web3(rpc, null, { transactionConfirmationBlocks: 1 }) @@ -386,6 +388,10 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) { PRIVATE_KEY = process.env.PRIVATE_KEY erc20ContractJson = require('./build/contracts/ERC20Mock.json') erc20tornadoJson = require('./build/contracts/ERC20Tornado.json') + const account = web3.eth.accounts.privateKeyToAccount('0x' + PRIVATE_KEY) + web3.eth.accounts.wallet.add('0x' + PRIVATE_KEY) + web3.eth.defaultAccount = account.address + senderAccount = account.address } // groth16 initialises a lot of Promises that will never be resolved, that's why we need to use process.exit to terminate the CLI groth16 = await buildGroth16() @@ -406,11 +412,6 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) { throw new Error() } tokenAddress = config.deployments[`netId${netId}`][currency].tokenAddress - const account = web3.eth.accounts.privateKeyToAccount('0x' + PRIVATE_KEY) - web3.eth.accounts.wallet.add('0x' + PRIVATE_KEY) - // eslint-disable-next-line require-atomic-updates - web3.eth.defaultAccount = account.address - senderAccount = account.address } catch(e) { console.error('There is no such tornado instance, check the currency and amount you provide') process.exit(1) @@ -422,14 +423,19 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) { async function main() { if (inBrowser) { - // window.deposit = deposit - // window.depositErc20 = depositErc20 - // window.withdraw = async () => { - // const note = prompt('Enter the note to withdraw') - // const recipient = (await web3.eth.getAccounts())[0] - // await withdraw(note, recipient) - // } - // init() + const instance = { currency: 'eth', amount: '0.1' } + await init(instance) + window.deposit = async () => { + await deposit(instance) + } + window.withdraw = async () => { + const noteString = prompt('Enter the note to withdraw') + const recipient = (await web3.eth.getAccounts())[0] + + const { currency, amount, netId, deposit } = parseNote(noteString) + await init({ noteNetId: netId, currency, amount }) + await withdraw({ deposit, currency, amount, recipient }) + } } else { program .option('-r, --rpc ', 'The RPC, CLI should interact with', 'http://localhost:8545') @@ -482,6 +488,7 @@ async function main() { }) try { await program.parseAsync(process.argv) + process.exit(0) } catch(e) { console.log('Error:', e) process.exit(1) @@ -489,4 +496,4 @@ async function main() { } } -main().then(process.exit(0)) +main() diff --git a/downloadKeys.js b/downloadKeys.js new file mode 100644 index 0000000..da966ea --- /dev/null +++ b/downloadKeys.js @@ -0,0 +1,43 @@ +const axios = require('axios') +const path = require('path') +const fs = require('fs') +const files = ['withdraw.json', 'withdraw_proving_key.bin', 'Verifier.sol', 'withdraw_verification_key.json'] +const circuitsPath = 'build/circuits' +const contractsPath = 'build/contracts' + +async function downloadFile({ url, path }) { + const writer = fs.createWriteStream(path) + + const response = await axios({ + url, + method: 'GET', + responseType: 'stream' + }) + + response.data.pipe(writer) + + return new Promise((resolve, reject) => { + writer.on('finish', resolve) + writer.on('error', reject) + }) +} + +async function main() { + const release = await axios.get('https://api.github.com/repos/tornadocash/tornado-core/releases/latest') + const { assets } = release.data + if (!fs.existsSync(circuitsPath)){ + fs.mkdirSync(circuitsPath, { recursive: true }) + fs.mkdirSync(contractsPath, { recursive: true }) + } + for(let asset of assets) { + if (files.includes(asset.name)) { + console.log(`Downloading ${asset.name} ...`) + await downloadFile({ + url: asset.browser_download_url, + path: path.resolve(__dirname, circuitsPath, asset.name) + }) + } + } +} + +main() diff --git a/package.json b/package.json index f4588f1..cec34d8 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "migrate:rinkeby": "npx truffle migrate --network rinkeby --reset", "migrate:mainnet": "npx truffle migrate --network mainnet", "eslint": "npx eslint --ignore-path .gitignore .", - "flat": "npx truffle-flattener contracts/ETHTornado.sol > ETHTornado_flat.sol && npx truffle-flattener contracts/ERC20Tornado.sol > ERC20Tornado_flat.sol" + "flat": "npx truffle-flattener contracts/ETHTornado.sol > ETHTornado_flat.sol && npx truffle-flattener contracts/ERC20Tornado.sol > ERC20Tornado_flat.sol", + "download": "node downloadKeys.js" }, "keywords": [], "author": "",