This commit is contained in:
Ayanami 2022-07-01 18:55:41 -03:00 committed by GitHub
commit fce5240348
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 379 additions and 157 deletions

View File

@ -6,6 +6,11 @@ TOKEN_AMOUNT=100000000000000000
ERC20_TOKEN= ERC20_TOKEN=
PRIVATE_KEY= PRIVATE_KEY=
RPC=
RELAYER=
TOR=
LOCALTX=
ONLYRPC=
#ERC20_TOKEN=0xf3e0d7bf58c5d455d31ef1c2d5375904df525105 #ERC20_TOKEN=0xf3e0d7bf58c5d455d31ef1c2d5375904df525105
#TOKEN_AMOUNT=1000000 #TOKEN_AMOUNT=1000000

View File

@ -121,9 +121,13 @@ Backed up invoice as ./backup-tornadoInvoice-eth-0.1-5-0x1b680c7d.txt
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. 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 ```bash
$ node cli.js depositInvoice <invoice> $ node cli.js depositInvoice <invoice> --rpc <rpc url> --tor <torPort>
``` ```
Note that `--tor <torPort>` is optional.
For RPC nodes please refer to the list of public RPC nodes below.
##### Example: ##### Example:
```bash ```bash
@ -144,9 +148,17 @@ Sender account balance is x.xxxxxxx ETH
#### To withdraw, you will need deposit note that matches with your deposit transaction. #### To withdraw, you will need deposit note that matches with your deposit transaction.
```bash ```bash
$ node cli.js withdraw <note> <recipient> $ node cli.js withdraw <note> <recipient> --rpc <rpc url> --relayer <relayer url> --tor <torPort>
``` ```
Note that `--relayer <relayer url>`, `--tor <torPort>` 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: ##### Example:
```bash ```bash

515
cli.js
View File

@ -22,7 +22,7 @@ const { GasPriceOracle } = require('gas-price-oracle');
const SocksProxyAgent = require('socks-proxy-agent'); const SocksProxyAgent = require('socks-proxy-agent');
const is_ip_private = require('private-ip'); const is_ip_private = require('private-ip');
let web3, torPort, tornado, tornadoContract, tornadoInstance, circuit, proving_key, groth16, erc20, senderAccount, netId, netName, netSymbol, doNotSubmitTx, multiCall, privateRpc, subgraph; let web3, torPort, tornado, tornadoContract, tornadoInstance, circuit, proving_key, groth16, erc20, senderAccount, netId, netName, netSymbol, doNotSubmitTx, multiCall, privateRpc, subgraph, isMobile;
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY; let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY;
/** Whether we are in a browser or node.js */ /** Whether we are in a browser or node.js */
@ -58,6 +58,7 @@ async function useMultiCall(queryArray) {
async function printETHBalance({ address, name }) { async function printETHBalance({ address, name }) {
const checkBalance = new BigNumber(await web3.eth.getBalance(address)).div(BigNumber(10).pow(18)); const checkBalance = new BigNumber(await web3.eth.getBalance(address)).div(BigNumber(10).pow(18));
console.log(`${name} balance is`, rmDecimalBN(checkBalance), `${netSymbol}`); console.log(`${name} balance is`, rmDecimalBN(checkBalance), `${netSymbol}`);
return checkBalance;
} }
/** Display ERC20 account balance */ /** Display ERC20 account balance */
@ -65,19 +66,28 @@ async function printERC20Balance({ address, name, tokenAddress }) {
let tokenDecimals, tokenBalance, tokenName, tokenSymbol; let tokenDecimals, tokenBalance, tokenName, tokenSymbol;
const erc20ContractJson = require('./build/contracts/ERC20Mock.json'); const erc20ContractJson = require('./build/contracts/ERC20Mock.json');
erc20 = tokenAddress ? new web3.eth.Contract(erc20ContractJson.abi, tokenAddress) : erc20; 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()]]); 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]); tokenDecimals = parseInt(tokenCall[1]);
tokenBalance = new BigNumber(tokenCall[0]).div(BigNumber(10).pow(tokenDecimals)); tokenBalance = new BigNumber(tokenCall[0]).div(BigNumber(10).pow(tokenDecimals));
tokenName = web3.eth.abi.decodeParameter('string', tokenCall[2]); tokenName = web3.eth.abi.decodeParameter('string', tokenCall[2]);
tokenSymbol = web3.eth.abi.decodeParameter('string', tokenCall[3]); tokenSymbol = web3.eth.abi.decodeParameter('string', tokenCall[3]);
} else { } else {
tokenDecimals = await erc20.methods.decimals().call(); [ tokenDecimals, tokenBalance, tokenName, tokenSymbol ] = await Promise.all([
tokenBalance = new BigNumber(await erc20.methods.balanceOf(address).call()).div(BigNumber(10).pow(tokenDecimals)); erc20.methods.decimals().call(),
tokenName = await erc20.methods.name().call(); erc20.methods.balanceOf(address).call(),
tokenSymbol = await erc20.methods.symbol().call(); erc20.methods.name().call(),
erc20.methods.symbol().call()
]);
tokenBalance = new BigNumber(tokenBalance).div(BigNumber(10).pow(tokenDecimals));
} }
console.log(`${name}`, tokenName, `Balance is`, rmDecimalBN(tokenBalance), tokenSymbol); console.log(`${name}`, tokenName, `Balance is`, rmDecimalBN(tokenBalance), tokenSymbol);
return tokenBalance;
} }
async function submitTransaction(signedTX) { async function submitTransaction(signedTX) {
@ -92,8 +102,10 @@ async function submitTransaction(signedTX) {
} }
async function generateTransaction(to, encodedData, value = 0) { async function generateTransaction(to, encodedData, value = 0) {
const nonce = await web3.eth.getTransactionCount(senderAccount); const [ nonce, gasPrice ] = await Promise.all([
let gasPrice = await fetchGasPrice(); web3.eth.getTransactionCount(senderAccount),
fetchGasPrice()
]);
let gasLimit; let gasLimit;
async function estimateGas() { async function estimateGas() {
@ -207,8 +219,10 @@ async function createInvoice({ currency, amount, chainId }) {
const invoiceString = `tornadoInvoice-${currency}-${amount}-${chainId}-${commitmentNote}`; const invoiceString = `tornadoInvoice-${currency}-${amount}-${chainId}-${commitmentNote}`;
console.log(`Your invoice for deposit: ${invoiceString}`); console.log(`Your invoice for deposit: ${invoiceString}`);
await backupNote({ currency, amount, netId: chainId, note, noteString }); await Promise.all([
await backupInvoice({ currency, amount, netId: chainId, commitmentNote, invoiceString }); backupNote({ currency, amount, netId: chainId, note, noteString }),
backupInvoice({ currency, amount, netId: chainId, commitmentNote, invoiceString })
]);
return (noteString, invoiceString); return (noteString, invoiceString);
} }
@ -237,25 +251,30 @@ async function deposit({ currency, amount, commitmentNote }) {
commitment = toHex(commitmentNote); commitment = toHex(commitmentNote);
} }
if (currency === netSymbol.toLowerCase()) { if (currency === netSymbol.toLowerCase()) {
await printETHBalance({ address: tornadoContract._address, name: 'Tornado contract' }); await Promise.all([
await printETHBalance({ address: senderAccount, name: 'Sender account' }); printETHBalance({ address: tornadoContract._address, name: 'Tornado contract' }),
printETHBalance({ address: senderAccount, name: 'Sender account' })
]);
const value = isTestRPC ? ETH_AMOUNT : fromDecimals({ amount, decimals: 18 }); const value = isTestRPC ? ETH_AMOUNT : fromDecimals({ amount, decimals: 18 });
console.log('Submitting deposit transaction'); console.log('Submitting deposit transaction');
await generateTransaction(contractAddress, tornado.methods.deposit(tornadoInstance, commitment, []).encodeABI(), value); await generateTransaction(contractAddress, tornado.methods.deposit(tornadoInstance, commitment, []).encodeABI(), value);
await printETHBalance({ address: tornadoContract._address, name: 'Tornado contract' }); await Promise.all([
await printETHBalance({ address: senderAccount, name: 'Sender account' }); printETHBalance({ address: tornadoContract._address, name: 'Tornado contract' }),
printETHBalance({ address: senderAccount, name: 'Sender account' })
]);
} else { } else {
// a token // a token
await printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' }); const [ balance1, balance2, allowance ] = await Promise.all([
await printERC20Balance({ address: senderAccount, name: 'Sender account' }); printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' }),
printERC20Balance({ address: senderAccount, name: 'Sender account' }),
erc20.methods.allowance(senderAccount, tornado._address).call({ from: senderAccount })
]);
const decimals = isTestRPC ? 18 : config.deployments[`netId${netId}`][currency].decimals; const decimals = isTestRPC ? 18 : config.deployments[`netId${netId}`][currency].decimals;
const tokenAmount = isTestRPC ? TOKEN_AMOUNT : fromDecimals({ amount, decimals }); const tokenAmount = isTestRPC ? TOKEN_AMOUNT : fromDecimals({ amount, decimals });
if (isTestRPC) { if (isTestRPC) {
console.log('Minting some test tokens to deposit'); console.log('Minting some test tokens to deposit');
await generateTransaction(erc20Address, erc20.methods.mint(senderAccount, tokenAmount).encodeABI()); await generateTransaction(erc20Address, erc20.methods.mint(senderAccount, tokenAmount).encodeABI());
} }
const allowance = await erc20.methods.allowance(senderAccount, tornado._address).call({ from: senderAccount });
console.log('Current allowance is', fromWei(allowance)); console.log('Current allowance is', fromWei(allowance));
if (toBN(allowance).lt(toBN(tokenAmount))) { if (toBN(allowance).lt(toBN(tokenAmount))) {
console.log('Approving tokens for deposit'); console.log('Approving tokens for deposit');
@ -264,8 +283,10 @@ async function deposit({ currency, amount, commitmentNote }) {
console.log('Submitting deposit transaction'); console.log('Submitting deposit transaction');
await generateTransaction(contractAddress, tornado.methods.deposit(tornadoInstance, commitment, []).encodeABI()); await generateTransaction(contractAddress, tornado.methods.deposit(tornadoInstance, commitment, []).encodeABI());
await printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' }); await Promise.all([
await printERC20Balance({ address: senderAccount, name: 'Sender account' }); printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' }),
printERC20Balance({ address: senderAccount, name: 'Sender account' })
]);
} }
if(!commitmentNote) { if(!commitmentNote) {
@ -300,15 +321,20 @@ async function generateMerkleProof(deposit, currency, amount) {
// Validate that our data is correct // Validate that our data is correct
const root = tree.root(); const root = tree.root();
let isValidRoot, isSpent; 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()]]) 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]); isValidRoot = web3.eth.abi.decodeParameter('bool', callContract[0]);
isSpent = web3.eth.abi.decodeParameter('bool', callContract[1]); isSpent = web3.eth.abi.decodeParameter('bool', callContract[1]);
} else { } else {
isValidRoot = await tornadoContract.methods.isKnownRoot(toHex(root)).call(); [ isValidRoot, isSpent ] = await Promise.all([
isSpent = await tornadoContract.methods.isSpent(toHex(deposit.nullifierHash)).call(); tornadoContract.methods.isKnownRoot(toHex(root)).call(),
tornadoContract.methods.isSpent(toHex(deposit.nullifierHash)).call()
]);
} }
assert(isValidRoot === true, 'Merkle tree is corrupted'); assert(isValidRoot === true, 'Merkle tree is corrupted. Some events could be missing, please try again.');
assert(isSpent === false, 'The note is already spent'); assert(isSpent === false, 'The note is already spent');
assert(leafIndex >= 0, 'The deposit is not found in the tree'); assert(leafIndex >= 0, 'The deposit is not found in the tree');
@ -346,6 +372,22 @@ async function generateProof({ deposit, currency, amount, recipient, relayerAddr
pathIndices: pathIndices pathIndices: pathIndices
} }
if (!groth16) {
const wasmMemory = isMobile ? 1000 : 2000;
// 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({ wasmInitialMemory: wasmMemory });
}
if (!circuit && !proving_key) {
if (inBrowser) {
circuit = await (await fetch('build/circuits/tornado.json')).json();
proving_key = await (await fetch('build/circuits/tornadoProvingKey.bin')).arrayBuffer();
} else {
circuit = require('./build/circuits/tornado.json');
proving_key = fs.readFileSync('build/circuits/tornadoProvingKey.bin').buffer;
}
}
console.log('Generating SNARK proof'); console.log('Generating SNARK proof');
console.time('Proof time'); console.time('Proof time');
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key); const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key);
@ -382,10 +424,13 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
if (torPort) { if (torPort) {
options = { httpsAgent: new SocksProxyAgent('socks5h://127.0.0.1:' + torPort), headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' } } options = { httpsAgent: new SocksProxyAgent('socks5h://127.0.0.1:' + torPort), headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' } }
} }
const relayerStatus = await axios.get(relayerURL + '/status', options); const [ relayerStatus, globalNetId ] = await Promise.all([
axios.get(relayerURL + '/status', options),
web3.eth.net.getId()
]);
const { rewardAccount, netId, ethPrices, tornadoServiceFee } = relayerStatus.data const { rewardAccount, netId, ethPrices, tornadoServiceFee } = relayerStatus.data
assert(netId === (await web3.eth.net.getId()) || netId === '*', 'This relay is for different network'); assert(netId === globalNetId || netId === '*', 'This relay is for different network');
console.log('Relay address:', rewardAccount); console.log('Relay address:', rewardAccount);
const gasPrice = await fetchGasPrice(); const gasPrice = await fetchGasPrice();
@ -427,6 +472,7 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
} }
} else { } else {
// using private key // using private key
assert(senderAccount, 'Private Key should be supplied through .env file if you want to make withdrawal without relayers');
// check if the address of recepient matches with the account of provided private key from environment to prevent accidental use of deposit address for withdrawal transaction. // check if the address of recepient matches with the account of provided private key from environment to prevent accidental use of deposit address for withdrawal transaction.
assert(recipient.toLowerCase() == senderAccount.toLowerCase(), 'Withdrawal recepient mismatches with the account of provided private key from environment file'); assert(recipient.toLowerCase() == senderAccount.toLowerCase(), 'Withdrawal recepient mismatches with the account of provided private key from environment file');
@ -459,15 +505,22 @@ async function send({ address, amount, tokenAddress }) {
const erc20ContractJson = require('./build/contracts/ERC20Mock.json'); const erc20ContractJson = require('./build/contracts/ERC20Mock.json');
erc20 = new web3.eth.Contract(erc20ContractJson.abi, tokenAddress); erc20 = new web3.eth.Contract(erc20ContractJson.abi, tokenAddress);
let tokenBalance, tokenDecimals, tokenSymbol; 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()]]); 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]); tokenBalance = new BigNumber(callToken[0]);
tokenDecimals = parseInt(callToken[1]); tokenDecimals = parseInt(callToken[1]);
tokenSymbol = web3.eth.abi.decodeParameter('string', callToken[2]); tokenSymbol = web3.eth.abi.decodeParameter('string', callToken[2]);
} else { } else {
tokenBalance = new BigNumber(await erc20.methods.balanceOf(senderAccount).call()); [ tokenBalance, tokenDecimals, tokenSymbol ] = await Promise.all([
tokenDecimals = await erc20.methods.decimals().call(); erc20.methods.balanceOf(senderAccount).call(),
tokenSymbol = await erc20.methods.symbol().call(); erc20.methods.decimals().call(),
erc20.methods.symbol().call()
]);
tokenBalance = new BigNumber(tokenBalance);
} }
const toSend = new BigNumber(amount).times(BigNumber(10).pow(tokenDecimals)); const toSend = new BigNumber(amount).times(BigNumber(10).pow(tokenDecimals));
if (tokenBalance.lt(toSend)) { if (tokenBalance.lt(toSend)) {
@ -478,7 +531,12 @@ async function send({ address, amount, tokenAddress }) {
await generateTransaction(tokenAddress, encodeTransfer); await generateTransaction(tokenAddress, encodeTransfer);
console.log('Sent', amount, tokenSymbol, 'to', address); console.log('Sent', amount, tokenSymbol, 'to', address);
} else { } else {
const balance = new BigNumber(await web3.eth.getBalance(senderAccount)); const fetchInfo = await Promise.all([
web3.eth.getBalance(senderAccount),
fetchGasPrice()
]);
const balance = new BigNumber(fetchInfo[0]);
const gasPrice = new BigNumber(fetchInfo[1]);
assert(balance.toNumber() !== 0, "You have 0 balance, can't send transaction"); assert(balance.toNumber() !== 0, "You have 0 balance, can't send transaction");
if (amount) { if (amount) {
toSend = new BigNumber(amount).times(BigNumber(10).pow(18)); toSend = new BigNumber(amount).times(BigNumber(10).pow(18));
@ -488,10 +546,9 @@ async function send({ address, amount, tokenAddress }) {
} }
} else { } else {
console.log('Amount not defined, sending all available amounts'); console.log('Amount not defined, sending all available amounts');
const gasPrice = new BigNumber(await fetchGasPrice());
const gasLimit = new BigNumber(21000); const gasLimit = new BigNumber(21000);
if (netId == 1) { if (netId == 1) {
const priorityFee = new BigNumber(await gasPrices(3)); const priorityFee = new BigNumber(gasPrices(3));
toSend = balance.minus(gasLimit.times(gasPrice.plus(priorityFee))); toSend = balance.minus(gasLimit.times(gasPrice.plus(priorityFee)));
} else { } else {
toSend = balance.minus(gasLimit.times(gasPrice)); toSend = balance.minus(gasLimit.times(gasPrice));
@ -727,7 +784,7 @@ function calculateFee({ currency, gasPrice, amount, refund, ethPrices, relayerSe
Math.floor(relayerServiceFee) === Number(relayerServiceFee) ? 0 : relayerServiceFee.toString().split('.')[1].length; Math.floor(relayerServiceFee) === Number(relayerServiceFee) ? 0 : relayerServiceFee.toString().split('.')[1].length;
const roundDecimal = 10 ** decimalsPoint; const roundDecimal = 10 ** decimalsPoint;
const total = toBN(fromDecimals({ amount, decimals })); const total = toBN(fromDecimals({ amount, decimals }));
const feePercent = total.mul(toBN(relayerServiceFee * roundDecimal)).div(toBN(roundDecimal * 100)); const feePercent = total.mul(toBN(Math.floor(relayerServiceFee * roundDecimal))).div(toBN(roundDecimal * 100));
const expense = toBN(gasPrice).mul(toBN(5e5)); const expense = toBN(gasPrice).mul(toBN(5e5));
let desiredFee; let desiredFee;
switch (currency) { switch (currency) {
@ -772,39 +829,27 @@ function waitForTxReceipt({ txHash, attempts = 60, delay = 1000 }) {
} }
function initJson(file) { function initJson(file) {
return new Promise((resolve, reject) => { if (fs.existsSync(file)) {
fs.readFile(file, 'utf8', (error, data) => { return JSON.parse(fs.readFileSync(file, { encoding: 'utf8' }));
if (error) { }
resolve([]); return [];
}
try {
resolve(JSON.parse(data));
} catch (error) {
resolve([]);
}
});
});
}; };
function loadCachedEvents({ type, currency, amount }) { function loadCachedEvents({ type, currency, amount }) {
try { const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`;
const module = require(`./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`); const events = initJson(fileName);
if (module) { if (events.length > 0) {
const events = module;
return {
events,
lastBlock: events[events.length - 1].blockNumber
}
}
} catch (err) {
console.log("Error fetching cached files, syncing from block", deployedBlockNumber);
return { return {
events: [], events,
lastBlock: deployedBlockNumber, lastBlock: events[events.length - 1].blockNumber
} }
} }
console.log("Error fetching cached files, syncing from block", deployedBlockNumber);
return {
events: [],
lastBlock: deployedBlockNumber,
}
} }
async function fetchEvents({ type, currency, amount }) { async function fetchEvents({ type, currency, amount }) {
@ -813,7 +858,7 @@ async function fetchEvents({ type, currency, amount }) {
} }
const cachedEvents = loadCachedEvents({ type, currency, amount }); const cachedEvents = loadCachedEvents({ type, currency, amount });
const startBlock = cachedEvents.lastBlock + 1; let startBlock = cachedEvents.lastBlock + 1;
console.log("Loaded cached",amount,currency.toUpperCase(),type,"events for",startBlock,"block"); console.log("Loaded cached",amount,currency.toUpperCase(),type,"events for",startBlock,"block");
console.log("Fetching",amount,currency.toUpperCase(),type,"events for",netName,"network"); console.log("Fetching",amount,currency.toUpperCase(),type,"events for",netName,"network");
@ -853,14 +898,6 @@ async function fetchEvents({ type, currency, amount }) {
}); });
} }
function mapLatestEvents() {
if (type === "deposit"){
mapDepositEvents();
} else {
mapWithdrawEvents();
}
}
async function fetchWeb3Events(i) { async function fetchWeb3Events(i) {
let j; let j;
if (i + chunks - 1 > targetBlock) { if (i + chunks - 1 > targetBlock) {
@ -868,10 +905,18 @@ async function fetchEvents({ type, currency, amount }) {
} else { } else {
j = i + chunks - 1; j = i + chunks - 1;
} }
await tornadoContract.getPastEvents(capitalizeFirstLetter(type), {
fromBlock: i, try {
toBlock: j, const getPastEvents = await tornadoContract.getPastEvents(capitalizeFirstLetter(type), {
}).then(r => { fetchedEvents = fetchedEvents.concat(r); console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", j) }, err => { console.error(i + " failed fetching", type, "events from node", err); process.exit(1); }).catch(console.log); fromBlock: i,
toBlock: j,
});
fetchedEvents = fetchedEvents.concat(getPastEvents);
console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", j);
} catch (e) {
console.error(i + " failed fetching", type, "events from node", e);
process.exit(1);
}
if (type === "deposit"){ if (type === "deposit"){
mapDepositEvents(); mapDepositEvents();
@ -880,12 +925,12 @@ async function fetchEvents({ type, currency, amount }) {
} }
} }
async function updateCache() { function updateCache() {
try { try {
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`; const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`;
const localEvents = await initJson(fileName); const localEvents = initJson(fileName);
const events = localEvents.concat(fetchedEvents); const events = localEvents.concat(fetchedEvents);
await fs.writeFileSync(fileName, JSON.stringify(events, null, 2), 'utf8'); fs.writeFileSync(fileName, JSON.stringify(events, null, 2), 'utf8');
} catch (error) { } catch (error) {
throw new Error('Writing cache file failed:',error); throw new Error('Writing cache file failed:',error);
} }
@ -894,6 +939,7 @@ async function fetchEvents({ type, currency, amount }) {
await updateCache(); await updateCache();
} }
} catch (error) { } catch (error) {
console.error(error);
throw new Error("Error while updating cache"); throw new Error("Error while updating cache");
process.exit(1); process.exit(1);
} }
@ -905,7 +951,7 @@ async function fetchEvents({ type, currency, amount }) {
options = { httpsAgent: new SocksProxyAgent('socks5h://127.0.0.1:' + torPort), headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' } }; options = { httpsAgent: new SocksProxyAgent('socks5h://127.0.0.1:' + torPort), headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' } };
} }
async function queryLatestTimestamp() { async function queryLatestBlockNumber() {
try { try {
const variables = { const variables = {
currency: currency.toString(), currency: currency.toString(),
@ -915,8 +961,8 @@ async function fetchEvents({ type, currency, amount }) {
const query = { const query = {
query: ` query: `
query($currency: String, $amount: String){ query($currency: String, $amount: String){
deposits(first: 1, orderBy: timestamp, orderDirection: desc, where: {currency: $currency, amount: $amount}) { deposits(first: 1, orderBy: blockNumber, orderDirection: desc, where: {currency: $currency, amount: $amount}) {
timestamp blockNumber
} }
} }
`, `,
@ -924,14 +970,14 @@ async function fetchEvents({ type, currency, amount }) {
} }
const querySubgraph = await axios.post(subgraph, query, options); const querySubgraph = await axios.post(subgraph, query, options);
const queryResult = querySubgraph.data.data.deposits; const queryResult = querySubgraph.data.data.deposits;
const result = queryResult[0].timestamp; const result = queryResult[0].blockNumber;
return Number(result); return Number(result);
} else { } else {
const query = { const query = {
query: ` query: `
query($currency: String, $amount: String){ query($currency: String, $amount: String){
withdrawals(first: 1, orderBy: timestamp, orderDirection: desc, where: {currency: $currency, amount: $amount}) { withdrawals(first: 1, orderBy: blockNumber, orderDirection: desc, where: {currency: $currency, amount: $amount}) {
timestamp blockNumber
} }
} }
`, `,
@ -939,7 +985,7 @@ async function fetchEvents({ type, currency, amount }) {
} }
const querySubgraph = await axios.post(subgraph, query, options); const querySubgraph = await axios.post(subgraph, query, options);
const queryResult = querySubgraph.data.data.withdrawals; const queryResult = querySubgraph.data.data.withdrawals;
const result = queryResult[0].timestamp; const result = queryResult[0].blockNumber;
return Number(result); return Number(result);
} }
} catch (error) { } catch (error) {
@ -947,18 +993,18 @@ async function fetchEvents({ type, currency, amount }) {
} }
} }
async function queryFromGraph(timestamp) { async function queryFromGraph(blockNumber) {
try { try {
const variables = { const variables = {
currency: currency.toString(), currency: currency.toString(),
amount: amount.toString(), amount: amount.toString(),
timestamp: timestamp blockNumber: blockNumber
} }
if (type === "deposit") { if (type === "deposit") {
const query = { const query = {
query: ` query: `
query($currency: String, $amount: String, $timestamp: Int){ query($currency: String, $amount: String, $blockNumber: Int){
deposits(orderBy: timestamp, first: 1000, where: {currency: $currency, amount: $amount, timestamp_gt: $timestamp}) { deposits(orderBy: blockNumber, first: 1000, where: {currency: $currency, amount: $amount, blockNumber_gte: $blockNumber}) {
blockNumber blockNumber
transactionHash transactionHash
commitment commitment
@ -984,8 +1030,8 @@ async function fetchEvents({ type, currency, amount }) {
} else { } else {
const query = { const query = {
query: ` query: `
query($currency: String, $amount: String, $timestamp: Int){ query($currency: String, $amount: String, $blockNumber: Int){
withdrawals(orderBy: timestamp, first: 1000, where: {currency: $currency, amount: $amount, timestamp_gt: $timestamp}) { withdrawals(orderBy: blockNumber, first: 1000, where: {currency: $currency, amount: $amount, blockNumber_gte: $blockNumber}) {
blockNumber blockNumber
transactionHash transactionHash
nullifier nullifier
@ -1014,12 +1060,28 @@ async function fetchEvents({ type, currency, amount }) {
} }
} }
async function updateCache(fetchedEvents) { function updateCache(fetchedEvents) {
try { try {
let events = [];
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`; const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`;
const localEvents = await initJson(fileName); const localEvents = initJson(fileName);
const events = localEvents.concat(fetchedEvents); const totalEvents = localEvents.concat(fetchedEvents);
await fs.writeFileSync(fileName, JSON.stringify(events, null, 2), 'utf8'); if (type === "deposit") {
const commit = new Set();
events = totalEvents.filter((r) => {
const notSameCommit = commit.has(r.commitment);
commit.add(r.commitment);
return !notSameCommit;
});
} else {
const nullifi = new Set();
events = totalEvents.filter((r) => {
const notSameNull = nullifi.has(r.nullifierHash);
nullifi.add(r.nullifierHash);
return !notSameNull;
});
}
fs.writeFileSync(fileName, JSON.stringify(events, null, 2), 'utf8');
} catch (error) { } catch (error) {
throw new Error('Writing cache file failed:',error); throw new Error('Writing cache file failed:',error);
} }
@ -1027,39 +1089,43 @@ async function fetchEvents({ type, currency, amount }) {
async function fetchGraphEvents() { async function fetchGraphEvents() {
console.log("Querying latest events from TheGraph"); console.log("Querying latest events from TheGraph");
const latestTimestamp = await queryLatestTimestamp(); const latestBlockNumber = await queryLatestBlockNumber();
if (latestTimestamp) { if (latestBlockNumber) {
const getCachedBlock = await web3.eth.getBlock(startBlock); for (let i = startBlock; i < latestBlockNumber;) {
const cachedTimestamp = getCachedBlock.timestamp;
for (let i = cachedTimestamp; i < latestTimestamp;) {
const result = await queryFromGraph(i); const result = await queryFromGraph(i);
if (Object.keys(result).length === 0) { if (Object.keys(result).length < 20) {
i = latestTimestamp; const block = new Set();
} else { const filteredResult = result.filter((r) => {
if (type === "deposit") { const notSameBlock = block.has(r.blockNumber);
const resultBlock = result[result.length - 1].blockNumber; block.add(r.blockNumber);
const resultTimestamp = result[result.length - 1].timestamp; return !notSameBlock;
await updateCache(result); });
i = resultTimestamp; if (Object.keys(filteredResult).length === 1) {
console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock)); i = latestBlockNumber;
} else { } else {
const resultBlock = result[result.length - 1].blockNumber; const resultBlock = result[result.length - 1].blockNumber;
const getResultBlock = await web3.eth.getBlock(resultBlock);
const resultTimestamp = getResultBlock.timestamp;
await updateCache(result); await updateCache(result);
i = resultTimestamp; i = resultBlock;
console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock)); console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock));
} }
} else {
const resultBlock = result[result.length - 1].blockNumber;
await updateCache(result);
i = resultBlock;
console.log("Fetched", amount, currency.toUpperCase(), type, "events to block:", Number(resultBlock));
} }
} }
return latestBlockNumber;
} else { } else {
console.log("Fallback to web3 events"); console.log("Fallback to web3 events");
await syncEvents(); return startBlock - 1;
} }
} }
await fetchGraphEvents(); await fetchGraphEvents();
startBlock = loadCachedEvents({ type, currency, amount }).lastBlock + 1;
await syncEvents();
} }
if (!privateRpc && !subgraph && !isTestRPC) { if (!privateRpc && subgraph && !isTestRPC) {
await syncGraphEvents(); await syncGraphEvents();
} else { } else {
await syncEvents(); await syncEvents();
@ -1069,7 +1135,7 @@ async function fetchEvents({ type, currency, amount }) {
const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`; const fileName = `./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`;
const updatedEvents = await initJson(fileName); const updatedEvents = await initJson(fileName);
const updatedBlock = updatedEvents[updatedEvents.length - 1].blockNumber; const updatedBlock = updatedEvents[updatedEvents.length - 1].blockNumber;
console.log("Cache updated for Tornado",type,amount,currency,"instance to block",updatedBlock,"successfully"); console.log("Cache updated for Tornado", type, amount, currency.toUpperCase(), "instance to block", updatedBlock);
console.log(`Total ${type}s:`, updatedEvents.length); console.log(`Total ${type}s:`, updatedEvents.length);
return updatedEvents; return updatedEvents;
} }
@ -1128,7 +1194,7 @@ function parseInvoice(invoiceString) {
async function loadDepositData({ amount, currency, deposit }) { async function loadDepositData({ amount, currency, deposit }) {
try { try {
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount }); const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount });
const eventWhenHappened = await cachedEvents.filter(function (event) { const eventWhenHappened = cachedEvents.filter(function (event) {
return event.commitment === deposit.commitmentHex; return event.commitment === deposit.commitmentHex;
})[0]; })[0];
@ -1138,8 +1204,11 @@ async function loadDepositData({ amount, currency, deposit }) {
const timestamp = eventWhenHappened.timestamp; const timestamp = eventWhenHappened.timestamp;
const txHash = eventWhenHappened.transactionHash; const txHash = eventWhenHappened.transactionHash;
const isSpent = await tornadoContract.methods.isSpent(deposit.nullifierHex).call();
const receipt = await web3.eth.getTransactionReceipt(txHash); const [ isSpent, receipt ] = await Promise.all([
tornadoContract.methods.isSpent(deposit.nullifierHex).call(),
web3.eth.getTransactionReceipt(txHash)
]);
return { return {
timestamp, timestamp,
@ -1192,8 +1261,6 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceC
}); });
contractJson = await (await fetch('build/contracts/TornadoProxy.abi.json')).json(); contractJson = await (await fetch('build/contracts/TornadoProxy.abi.json')).json();
instanceJson = await (await fetch('build/contracts/Instance.abi.json')).json(); instanceJson = await (await fetch('build/contracts/Instance.abi.json')).json();
circuit = await (await fetch('build/circuits/tornado.json')).json();
proving_key = await (await fetch('build/circuits/tornadoProvingKey.bin')).arrayBuffer();
MERKLE_TREE_HEIGHT = 20; MERKLE_TREE_HEIGHT = 20;
ETH_AMOUNT = 1e18; ETH_AMOUNT = 1e18;
TOKEN_AMOUNT = 1e19; TOKEN_AMOUNT = 1e19;
@ -1239,8 +1306,6 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceC
} }
contractJson = require('./build/contracts/TornadoProxy.abi.json'); contractJson = require('./build/contracts/TornadoProxy.abi.json');
instanceJson = require('./build/contracts/Instance.abi.json'); instanceJson = require('./build/contracts/Instance.abi.json');
circuit = require('./build/circuits/tornado.json');
proving_key = fs.readFileSync('build/circuits/tornadoProvingKey.bin').buffer;
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20; MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20;
ETH_AMOUNT = process.env.ETH_AMOUNT; ETH_AMOUNT = process.env.ETH_AMOUNT;
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT; TOKEN_AMOUNT = process.env.TOKEN_AMOUNT;
@ -1261,8 +1326,6 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100', balanceC
erc20ContractJson = require('./build/contracts/ERC20Mock.json'); erc20ContractJson = require('./build/contracts/ERC20Mock.json');
erc20tornadoJson = require('./build/contracts/ERC20Tornado.json'); erc20tornadoJson = require('./build/contracts/ERC20Tornado.json');
} }
// 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();
netId = await web3.eth.net.getId(); netId = await web3.eth.net.getId();
netName = getCurrentNetworkName(); netName = getCurrentNetworkName();
netSymbol = getCurrentNetworkSymbol(); netSymbol = getCurrentNetworkSymbol();
@ -1330,7 +1393,7 @@ async function main() {
.option('-r, --rpc <URL>', 'The RPC that CLI should interact with', 'http://localhost:8545') .option('-r, --rpc <URL>', 'The RPC that CLI should interact with', 'http://localhost:8545')
.option('-R, --relayer <URL>', 'Withdraw via relayer') .option('-R, --relayer <URL>', 'Withdraw via relayer')
.option('-T, --tor <PORT>', 'Optional tor port') .option('-T, --tor <PORT>', 'Optional tor port')
.option('-L, --local', 'Local Node - Does not submit signed transaction to the node') .option('-L, --localtx', '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'); .option('-o, --onlyrpc', 'Only rpc mode - Does not enable thegraph api nor remote ip detection');
program program
.command('createNote <currency> <amount> <chainId>') .command('createNote <currency> <amount> <chainId>')
@ -1347,12 +1410,29 @@ async function main() {
'Submit a deposit of invoice from default eth account and return the resulting note.' 'Submit a deposit of invoice from default eth account and return the resulting note.'
) )
.action(async (invoice) => { .action(async (invoice) => {
if (program.onlyrpc) { let rpc, localtx;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.LOCALTX) {
localtx = process.env.LOCALTX;
} else {
localtx = program.localtx;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
torPort = program.tor;
const { currency, amount, netId, commitmentNote } = parseInvoice(invoice); const { currency, amount, netId, commitmentNote } = parseInvoice(invoice);
await init({ rpc: program.rpc, currency, amount, localMode: program.local }); await init({ rpc: rpc, currency, amount, localMode: localtx });
console.log("Creating", currency.toUpperCase(), amount, "deposit for", netName, "Tornado Cash Instance"); console.log("Creating", currency.toUpperCase(), amount, "deposit for", netName, "Tornado Cash Instance");
await deposit({ currency, amount, commitmentNote }); await deposit({ currency, amount, commitmentNote });
}); });
@ -1362,12 +1442,29 @@ 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.' '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) => { .action(async (currency, amount) => {
if (program.onlyrpc) { let rpc, localtx;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.LOCALTX) {
localtx = process.env.LOCALTX;
} else {
localtx = program.localtx;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
currency = currency.toLowerCase(); currency = currency.toLowerCase();
torPort = program.tor; await init({ rpc: rpc, currency, amount, localMode: localtx });
await init({ rpc: program.rpc, currency, amount, localMode: program.local });
await deposit({ currency, amount }); await deposit({ currency, amount });
}); });
program program
@ -1376,30 +1473,64 @@ 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.' '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) => { .action(async (noteString, recipient, refund) => {
if (program.onlyrpc) { let rpc, localtx, relayer;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.LOCALTX) {
localtx = process.env.LOCALTX;
} else {
localtx = program.localtx;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
if (process.env.RELAYER) {
relayer = process.env.RELAYER;
} else {
relayer = program.relayer;
}
const { currency, amount, netId, deposit } = parseNote(noteString); const { currency, amount, netId, deposit } = parseNote(noteString);
torPort = program.tor; await init({ rpc: rpc, noteNetId: netId, currency, amount, localMode: localtx });
await init({ rpc: program.rpc, noteNetId: netId, currency, amount, localMode: program.local });
await withdraw({ await withdraw({
deposit, deposit,
currency, currency,
amount, amount,
recipient, recipient,
refund, refund,
relayerURL: program.relayer relayerURL: relayer
}); });
}); });
program program
.command('balance [address] [token_address]') .command('balance [address] [token_address]')
.description('Check ETH and ERC20 balance') .description('Check ETH and ERC20 balance')
.action(async (address, tokenAddress) => { .action(async (address, tokenAddress) => {
if (program.onlyrpc) { let rpc;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
torPort = program.tor; await init({ rpc: rpc, balanceCheck: true });
await init({ rpc: program.rpc, balanceCheck: true });
if (!address && senderAccount) { if (!address && senderAccount) {
console.log("Using address", senderAccount, "from private key"); console.log("Using address", senderAccount, "from private key");
address = senderAccount; address = senderAccount;
@ -1413,22 +1544,51 @@ async function main() {
.command('send <address> [amount] [token_address]') .command('send <address> [amount] [token_address]')
.description('Send ETH or ERC to address') .description('Send ETH or ERC to address')
.action(async (address, amount, tokenAddress) => { .action(async (address, amount, tokenAddress) => {
if (program.onlyrpc) { let rpc, localtx;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.LOCALTX) {
localtx = process.env.LOCALTX;
} else {
localtx = program.localtx;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
torPort = program.tor; await init({ rpc: rpc, balanceCheck: true, localMode: localtx });
await init({ rpc: program.rpc, balanceCheck: true, localMode: program.local });
await send({ address, amount, tokenAddress }); await send({ address, amount, tokenAddress });
}); });
program program
.command('broadcast <signedTX>') .command('broadcast <signedTX>')
.description('Submit signed TX to the remote node') .description('Submit signed TX to the remote node')
.action(async (signedTX) => { .action(async (signedTX) => {
if (program.onlyrpc) { let rpc;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
torPort = program.tor; await init({ rpc: rpc, balanceCheck: true });
await init({ rpc: program.rpc, balanceCheck: true });
await submitTransaction(signedTX); await submitTransaction(signedTX);
}); });
program program
@ -1437,12 +1597,24 @@ 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.' '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) => { .action(async (noteString) => {
if (program.onlyrpc) { let rpc;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
const { currency, amount, netId, deposit } = parseNote(noteString); const { currency, amount, netId, deposit } = parseNote(noteString);
torPort = program.tor; await init({ rpc: rpc, noteNetId: netId, currency, amount });
await init({ rpc: program.rpc, noteNetId: netId, currency, amount });
const depositInfo = await loadDepositData({ amount, currency, deposit }); const depositInfo = await loadDepositData({ amount, currency, deposit });
const depositDate = new Date(depositInfo.timestamp * 1000); const depositDate = new Date(depositInfo.timestamp * 1000);
console.log('\n=============Deposit================='); console.log('\n=============Deposit=================');
@ -1475,13 +1647,25 @@ async function main() {
'Sync the local cache file of deposit / withdrawal events for specific currency.' 'Sync the local cache file of deposit / withdrawal events for specific currency.'
) )
.action(async (type, currency, amount) => { .action(async (type, currency, amount) => {
if (program.onlyrpc) { let rpc;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true; privateRpc = true;
} }
console.log("Starting event sync command"); console.log("Starting event sync command");
currency = currency.toLowerCase(); currency = currency.toLowerCase();
torPort = program.tor; await init({ rpc: rpc, type, currency, amount });
await init({ rpc: program.rpc, type, currency, amount });
const cachedEvents = await fetchEvents({ type, currency, amount }); const cachedEvents = await fetchEvents({ type, currency, amount });
console.log("Synced event for", type, amount, currency.toUpperCase(), netName, "Tornado instance to block", cachedEvents[cachedEvents.length - 1].blockNumber); console.log("Synced event for", type, amount, currency.toUpperCase(), netName, "Tornado instance to block", cachedEvents[cachedEvents.length - 1].blockNumber);
}); });
@ -1493,7 +1677,28 @@ async function main() {
console.log('Start performing ETH deposit-withdraw test'); console.log('Start performing ETH deposit-withdraw test');
let currency = 'eth'; let currency = 'eth';
let amount = '0.1'; let amount = '0.1';
await init({ rpc: program.rpc, currency, amount }); let rpc, relayer;
if (process.env.RPC) {
rpc = process.env.RPC;
} else {
rpc = program.rpc;
}
if (process.env.TOR) {
torPort = process.env.TOR;
} else if (program.tor) {
torPort = program.tor;
}
if (process.env.ONLYRPC) {
privateRpc = true;
} else if (program.onlyrpc) {
privateRpc = true;
}
if (process.env.RELAYER) {
relayer = process.env.RELAYER;
} else {
relayer = program.relayer;
}
await init({ rpc: rpc, currency, amount });
let noteString = await deposit({ currency, amount }); let noteString = await deposit({ currency, amount });
let parsedNote = parseNote(noteString); let parsedNote = parseNote(noteString);
await withdraw({ await withdraw({
@ -1501,13 +1706,13 @@ async function main() {
currency, currency,
amount, amount,
recipient: senderAccount, recipient: senderAccount,
relayerURL: program.relayer relayerURL: relayer
}); });
console.log('\nStart performing DAI deposit-withdraw test'); console.log('\nStart performing DAI deposit-withdraw test');
currency = 'dai'; currency = 'dai';
amount = '100'; amount = '100';
await init({ rpc: program.rpc, currency, amount }); await init({ rpc: rpc, currency, amount });
noteString = await deposit({ currency, amount }); noteString = await deposit({ currency, amount });
parsedNote = parseNote(noteString); parsedNote = parseNote(noteString);
await withdraw({ await withdraw({
@ -1516,7 +1721,7 @@ async function main() {
amount, amount,
recipient: senderAccount, recipient: senderAccount,
refund: '0.02', refund: '0.02',
relayerURL: program.relayer relayerURL: relayer
}); });
}); });
try { try {