rename variables

This commit is contained in:
poma 2019-12-13 20:49:19 +07:00
parent d9f4b16076
commit 4114f7b52c
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
13 changed files with 169 additions and 169 deletions

6
.gitignore vendored
View File

@ -1,7 +1,7 @@
build
.vscode
/index.js
Mixer_flat.sol
Tornado_flat.sol
# Created by .ignore support plugin (hsz.mobi)
### Node template
@ -94,5 +94,5 @@ typings/
# DynamoDB Local files
.dynamodb/
ERC20Mixer_flat.sol
ETHMixer_flat.sol
ERC20Tornado_flat.sol
ETHTornado_flat.sol

View File

@ -1,6 +1,6 @@
# Tornado mixer [![Build Status](https://travis-ci.org/tornadocash/tornado-core.svg?branch=master)](https://travis-ci.org/tornadocash/tornado-core)
# Tornado Privacy Solution [![Build Status](https://travis-ci.org/tornadocash/tornado-core.svg?branch=master)](https://travis-ci.org/tornadocash/tornado-core)
Tornado is a non-custodial Ethereum and ERC20 mixer based on zkSNARKs. It improves transaction privacy by breaking the on-chain link between recipient and destination addresses. It uses a smart contract that accepts ETH deposits that can be withdrawn by a different address. Whenever ETH is withdrawn by the new address, there is no way to link the withdrawal to the deposit, ensuring complete privacy.
Tornado is a non-custodial Ethereum and ERC20 privacy solution based on zkSNARKs. It improves transaction privacy by breaking the on-chain link between recipient and destination addresses. It uses a smart contract that accepts ETH deposits that can be withdrawn by a different address. Whenever ETH is withdrawn by the new address, there is no way to link the withdrawal to the deposit, ensuring complete privacy.
To make a deposit user generates a secret and sends its hash (called a commitment) along with the deposit amount to the Tornado smart contract. The contract accepts the deposit and adds the commitment to its list of deposits.
@ -15,12 +15,12 @@ You can read more about it in [this medium article](https://medium.com/@tornado.
- Circuit Proof time = 6116ms (1071 + 347 * tree_depth)
- Serverless
![mixer image](./mixer.png)
![image](diagram.png)
## Security risks
* Cryptographic tools used by mixer (zkSNARKS, Pedersen commitment, MiMC hash) are yet NOT extensively audited by cryptographic experts and may be vulnerable
* Cryptographic tools used by Tornado (zkSNARKS, Pedersen commitment, MiMC hash) are yet NOT extensively audited by cryptographic experts and may be vulnerable
* Note: we use MiMC hash only for merkle tree, so even if a preimage attack on MiMC is discovered, it will not allow to deanonymize users. To drain funds attacker needs to be able to generate arbitrary hash collisions, which is a pretty strong assumption.
* Bugs in contract. Even though we have an extensive experience in smart contract security audits, we can still make mistakes. An external audit is needed to reduce probablility of bugs. Our mixer is currently being audited, stay tuned.
* Bugs in contract. Even though we have an extensive experience in smart contract security audits, we can still make mistakes. An external audit is needed to reduce probablility of bugs. Our code is currently being audited, stay tuned.
* Relayer is frontrunnable. When relayer submits a transaction someone can see it in tx pool and frontrun it with higher gas price to get the fee and drain relayer funds.
* Workaround: we can set high gas price so that (almost) all fee is used on gas
* Second workaround: allow only single hardcoded relayer, we use this approach for now
@ -51,13 +51,13 @@ Use browser version on Kovan:
1. Open `localhost:8080`
Use with command line version with Ganache:
### ETHMixer
### ETHTornado
1. `npm run migrate:dev`
1. `./cli.js deposit`
1. `./cli.js withdraw <note from previous step> <destination eth address>`
1. `./cli.js balance <destination eth address>`
### ERC20Mixer
### ERC20Tornado
1. `npm run migrate:dev`
1. `./cli.js depositErc20`
1. `./cli.js withdrawErc20 <note from previous step> <destination eth address> <relayer eth address>`
@ -76,7 +76,7 @@ If you want, you can point the app to existing tornado contracts on Mainnet or K
1. `npx truffle migrate --network kovan --reset --f 2 --to 3`
1. `npx truffle migrate --network kovan --reset --f 5`
**Note**. If you want to reuse the same verifier for all the mixers, then after you deployed one of the mixers you should only run 4th or 5th migration for ETH or ERC20 mixers respectively (`--f 4 --to 4` or `--f 5`).
**Note**. If you want to reuse the same verifier for all the instances, then after you deployed one of the instances you should only run 4th or 5th migration for ETH or ERC20 contracts respectively (`--f 4 --to 4` or `--f 5`).
## Credits

66
cli.js
View File

@ -14,7 +14,7 @@ const buildGroth16 = require('websnark/src/groth16')
const websnarkUtils = require('websnark/src/utils')
const { toWei, fromWei } = require('web3-utils')
let web3, mixer, erc20mixer, circuit, proving_key, groth16, erc20, senderAccount
let web3, tornado, erc20tornado, circuit, proving_key, groth16, erc20, senderAccount
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, ERC20_TOKEN
/** Whether we are in a browser or node.js */
@ -56,7 +56,7 @@ async function deposit() {
const deposit = createDeposit(rbigint(31), rbigint(31))
console.log('Submitting deposit transaction')
await mixer.methods.deposit(toHex(deposit.commitment)).send({ value: ETH_AMOUNT, from: senderAccount, gas:1e6 })
await tornado.methods.deposit(toHex(deposit.commitment)).send({ value: ETH_AMOUNT, from: senderAccount, gas:1e6 })
const note = toHex(deposit.preimage, 62)
console.log('Your note:', note)
@ -75,10 +75,10 @@ async function depositErc20() {
}
console.log('Approving tokens for deposit')
await erc20.methods.approve(erc20mixer._address, TOKEN_AMOUNT).send({ from: senderAccount, gas:1e6 })
await erc20.methods.approve(erc20tornado._address, TOKEN_AMOUNT).send({ from: senderAccount, gas:1e6 })
console.log('Submitting deposit transaction')
await erc20mixer.methods.deposit(toHex(deposit.commitment)).send({ from: senderAccount, gas:1e6 })
await erc20tornado.methods.deposit(toHex(deposit.commitment)).send({ from: senderAccount, gas:1e6 })
const note = toHex(deposit.preimage, 62)
console.log('Your note:', note)
@ -89,12 +89,12 @@ async function depositErc20() {
* Generate merkle tree for a deposit.
* Download deposit events from the contract, reconstructs merkle tree, finds our deposit leaf
* in it and generates merkle proof
* @param contract Mixer contract address
* @param contract Tornado contract address
* @param deposit Deposit object
*/
async function generateMerkleProof(contract, deposit) {
// Get all deposit events from smart contract and assemble merkle tree from them
console.log('Getting current state from mixer contract')
console.log('Getting current state from tornado contract')
const events = await contract.getPastEvents('Deposit', { fromBlock: contract.deployedBlock, toBlock: 'latest' })
const leaves = events
.sort((a, b) => a.returnValues.leafIndex - b.returnValues.leafIndex) // Sort events in chronological order
@ -118,7 +118,7 @@ async function generateMerkleProof(contract, deposit) {
/**
* Generate SNARK proof for withdrawal
* @param contract Mixer contract address
* @param contract Tornado contract address
* @param note Note string
* @param recipient Funds recipient
* @param relayer Relayer address
@ -174,10 +174,10 @@ async function generateProof(contract, note, recipient, relayer = 0, fee = 0, re
* @param recipient Recipient address
*/
async function withdraw(note, recipient) {
const { proof, args } = await generateProof(mixer, note, recipient)
const { proof, args } = await generateProof(tornado, note, recipient)
console.log('Submitting withdraw transaction')
await mixer.methods.withdraw(proof, ...args).send({ from: senderAccount, gas: 1e6 })
await tornado.methods.withdraw(proof, ...args).send({ from: senderAccount, gas: 1e6 })
console.log('Done')
}
@ -187,10 +187,10 @@ async function withdraw(note, recipient) {
* @param recipient Recipient address
*/
async function withdrawErc20(note, recipient) {
const { proof, args } = await generateProof(erc20mixer, note, recipient)
const { proof, args } = await generateProof(erc20tornado, note, recipient)
console.log('Submitting withdraw transaction')
await erc20mixer.methods.withdraw(proof, ...args).send({ from: senderAccount, gas: 1e6 })
await erc20tornado.methods.withdraw(proof, ...args).send({ from: senderAccount, gas: 1e6 })
console.log('Done')
}
@ -207,10 +207,10 @@ async function withdrawRelay(note, recipient, relayUrl) {
console.log('Relay address: ', relayerAddress)
const fee = bigInt(toWei(gasPrices.fast.toString(), 'gwei')).mul(bigInt(1e6))
const { proof, args } = await generateProof(mixer, note, recipient, relayerAddress, fee)
const { proof, args } = await generateProof(tornado, note, recipient, relayerAddress, fee)
console.log('Sending withdraw transaction through relay')
const resp2 = await axios.post(relayUrl + '/relay', { contract: mixer._address, proof: { proof, publicSignals: args } })
const resp2 = await axios.post(relayUrl + '/relay', { contract: tornado._address, proof: { proof, publicSignals: args } })
console.log(`Transaction submitted through relay, tx hash: ${resp2.data.txHash}`)
let receipt = await waitForTxReceipt(resp2.data.txHash)
@ -232,10 +232,10 @@ async function withdrawRelayErc20(note, recipient, relayUrl) {
const refund = bigInt(toWei('0.001'))
const fee = bigInt(toWei(gasPrices.fast.toString(), 'gwei')).mul(bigInt(1e6)).add(refund).mul(bigInt(fromWei(ethPriceInDai.toString())))
const { proof, args } = await generateProof(erc20mixer, note, recipient, relayerAddress, fee, refund)
const { proof, args } = await generateProof(erc20tornado, note, recipient, relayerAddress, fee, refund)
console.log('Sending withdraw transaction through relay')
const resp2 = await axios.post(relayUrl + '/relay', { contract: erc20mixer._address, proof: { proof, publicSignals: args } })
const resp2 = await axios.post(relayUrl + '/relay', { contract: erc20tornado._address, proof: { proof, publicSignals: args } })
console.log(`Transaction submitted through relay, tx hash: ${resp2.data.txHash}`)
let receipt = await waitForTxReceipt(resp2.data.txHash)
@ -271,12 +271,12 @@ function waitForTxReceipt(txHash, attempts = 60, delay = 1000) {
* Init web3, contracts, and snark
*/
async function init() {
let contractJson, erc20ContractJson, erc20mixerJson
let contractJson, erc20ContractJson, erc20tornadoJson
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/ETHMixer.json')).json()
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
@ -285,7 +285,7 @@ async function init() {
} else {
// Initialize from local node
web3 = new Web3('http://localhost:8545', null, { transactionConfirmationBlocks: 1 })
contractJson = require('./build/contracts/ETHMixer.json')
contractJson = require('./build/contracts/ETHTornado.json')
circuit = require('./build/circuits/withdraw.json')
proving_key = fs.readFileSync('build/circuits/withdraw_proving_key.bin').buffer
require('dotenv').config()
@ -294,19 +294,19 @@ async function init() {
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT
ERC20_TOKEN = process.env.ERC20_TOKEN
erc20ContractJson = require('./build/contracts/ERC20Mock.json')
erc20mixerJson = require('./build/contracts/ERC20Mixer.json')
erc20tornadoJson = require('./build/contracts/ERC20Tornado.json')
}
groth16 = await buildGroth16()
let netId = await web3.eth.net.getId()
if (contractJson.networks[netId]) {
const tx = await web3.eth.getTransaction(contractJson.networks[netId].transactionHash)
mixer = new web3.eth.Contract(contractJson.abi, contractJson.networks[netId].address)
mixer.deployedBlock = tx.blockNumber
tornado = new web3.eth.Contract(contractJson.abi, contractJson.networks[netId].address)
tornado.deployedBlock = tx.blockNumber
}
const tx3 = await web3.eth.getTransaction(erc20mixerJson.networks[netId].transactionHash)
erc20mixer = new web3.eth.Contract(erc20mixerJson.abi, erc20mixerJson.networks[netId].address)
erc20mixer.deployedBlock = tx3.blockNumber
const tx3 = await web3.eth.getTransaction(erc20tornadoJson.networks[netId].transactionHash)
erc20tornado = new web3.eth.Contract(erc20tornadoJson.abi, erc20tornadoJson.networks[netId].address)
erc20tornado.deployedBlock = tx3.blockNumber
if(ERC20_TOKEN === '') {
erc20 = new web3.eth.Contract(erc20ContractJson.abi, erc20ContractJson.networks[netId].address)
@ -333,7 +333,7 @@ function printHelp(code = 0) {
Check address balance
$ ./cli.js balance <address>
Perform an automated test
$ ./cli.js test
$ ./cli.js testRelay
@ -357,10 +357,10 @@ async function runConsole(args) {
case 'deposit':
if (args.length === 1) {
await init()
await printBalance(mixer._address, 'Mixer')
await printBalance(tornado._address, 'Tornado')
await printBalance(senderAccount, 'Sender account')
await deposit()
await printBalance(mixer._address, 'Mixer')
await printBalance(tornado._address, 'Tornado')
await printBalance(senderAccount, 'Sender account')
} else {
printHelp(1)
@ -369,10 +369,10 @@ async function runConsole(args) {
case 'depositErc20':
if (args.length === 1) {
await init()
await printBalance(erc20mixer._address, 'Mixer')
await printBalance(erc20tornado._address, 'Tornado')
await printBalance(senderAccount, 'Sender account')
await depositErc20()
await printBalance(erc20mixer._address, 'Mixer')
await printBalance(erc20tornado._address, 'Tornado')
await printBalance(senderAccount, 'Sender account')
} else {
printHelp(1)
@ -389,14 +389,14 @@ async function runConsole(args) {
case 'withdraw':
if (args.length >= 3 && args.length <= 4 && /^0x[0-9a-fA-F]{124}$/.test(args[1]) && /^0x[0-9a-fA-F]{40}$/.test(args[2])) {
await init()
await printBalance(mixer._address, 'Mixer')
await printBalance(tornado._address, 'Tornado')
await printBalance(args[2], 'Recipient account')
if (args[3]) {
await withdrawRelay(args[1], args[2], args[3])
} else {
await withdraw(args[1], args[2])
}
await printBalance(mixer._address, 'Mixer')
await printBalance(tornado._address, 'Tornado')
await printBalance(args[2], 'Recipient account')
} else {
printHelp(1)
@ -405,14 +405,14 @@ async function runConsole(args) {
case 'withdrawErc20':
if (args.length >= 3 && args.length <= 4 && /^0x[0-9a-fA-F]{124}$/.test(args[1]) && /^0x[0-9a-fA-F]{40}$/.test(args[2])) {
await init()
await printBalance(erc20mixer._address, 'Mixer')
await printBalance(erc20tornado._address, 'Tornado')
await printBalance(args[2], 'Recipient account')
if (args[3]) {
await withdrawRelayErc20(args[1], args[2], args[3])
} else {
await withdrawErc20(args[1], args[2])
}
await printBalance(erc20mixer._address, 'Mixer')
await printBalance(erc20tornado._address, 'Tornado')
await printBalance(args[2], 'Recipient account')
} else {
printHelp(1)

View File

@ -11,9 +11,9 @@
pragma solidity ^0.5.8;
import "./Mixer.sol";
import "./Tornado.sol";
contract ERC20Mixer is Mixer {
contract ERC20Tornado is Tornado {
address public token;
constructor(
@ -22,12 +22,12 @@ contract ERC20Mixer is Mixer {
uint32 _merkleTreeHeight,
address _operator,
address _token
) Mixer(_verifier, _denomination, _merkleTreeHeight, _operator) public {
) Tornado(_verifier, _denomination, _merkleTreeHeight, _operator) public {
token = _token;
}
function _processDeposit() internal {
require(msg.value == 0, "ETH value is supposed to be 0 for ERC20 mixer");
require(msg.value == 0, "ETH value is supposed to be 0 for ERC20 instance");
_safeErc20TransferFrom(msg.sender, address(this), denomination);
}

View File

@ -11,15 +11,15 @@
pragma solidity ^0.5.8;
import "./Mixer.sol";
import "./Tornado.sol";
contract ETHMixer is Mixer {
contract ETHTornado is Tornado {
constructor(
IVerifier _verifier,
uint256 _denomination,
uint32 _merkleTreeHeight,
address _operator
) Mixer(_verifier, _denomination, _merkleTreeHeight, _operator) public {
) Tornado(_verifier, _denomination, _merkleTreeHeight, _operator) public {
}
function _processDeposit() internal {
@ -28,8 +28,8 @@ contract ETHMixer is Mixer {
function _processWithdraw(address payable _recipient, address payable _relayer, uint256 _fee, uint256 _refund) internal {
// sanity checks
require(msg.value == 0, "Message value is supposed to be zero for ETH mixer");
require(_refund == 0, "Refund value is supposed to be zero for ETH mixer");
require(msg.value == 0, "Message value is supposed to be zero for ETH instance");
require(_refund == 0, "Refund value is supposed to be zero for ETH instance");
(bool success, ) = _recipient.call.value(denomination - _fee)("");
require(success, "payment to _recipient did not go thru");

View File

@ -18,7 +18,7 @@ contract IVerifier {
function verifyProof(bytes memory _proof, uint256[6] memory _input) public returns(bool);
}
contract Mixer is MerkleTreeWithHistory, ReentrancyGuard {
contract Tornado is MerkleTreeWithHistory, ReentrancyGuard {
uint256 public denomination;
mapping(bytes32 => bool) public nullifierHashes;
// we store all commitments just to prevent accidental deposits with the same commitment
@ -56,7 +56,7 @@ contract Mixer is MerkleTreeWithHistory, ReentrancyGuard {
}
/**
@dev Deposit funds into mixer. The caller must send (for ETH) or approve (for ERC20) value equal to or `denomination` of this mixer.
@dev Deposit funds into the contract. The caller must send (for ETH) or approve (for ERC20) value equal to or `denomination` of this instance.
@param _commitment the note commitment, which is PedersenHash(nullifier + secret)
*/
function deposit(bytes32 _commitment) external payable nonReentrant {
@ -73,9 +73,9 @@ contract Mixer is MerkleTreeWithHistory, ReentrancyGuard {
function _processDeposit() internal;
/**
@dev Withdraw a deposit from the mixer. `proof` is a zkSNARK proof data, and input is an array of circuit public inputs
@dev Withdraw a deposit from the contract. `proof` is a zkSNARK proof data, and input is an array of circuit public inputs
`input` array consists of:
- merkle root of all deposits in the mixer
- merkle root of all deposits in the contract
- hash of unique deposit nullifier to prevent double spends
- the recipient of funds
- optional fee that goes to the transaction sender (usually a relay)

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>Snark mixer test</title>
<title>Tornado test</title>
</head>
<body>
<p>

View File

@ -1,6 +1,6 @@
/* global artifacts */
require('dotenv').config({ path: '../.env' })
const ETHMixer = artifacts.require('ETHMixer')
const ETHTornado = artifacts.require('ETHTornado')
const Verifier = artifacts.require('Verifier')
const hasherContract = artifacts.require('Hasher')
@ -10,8 +10,8 @@ module.exports = function(deployer, network, accounts) {
const { MERKLE_TREE_HEIGHT, ETH_AMOUNT } = process.env
const verifier = await Verifier.deployed()
const hasherInstance = await hasherContract.deployed()
await ETHMixer.link(hasherContract, hasherInstance.address)
const mixer = await deployer.deploy(ETHMixer, verifier.address, ETH_AMOUNT, MERKLE_TREE_HEIGHT, accounts[0])
console.log('ETHMixer\'s address ', mixer.address)
await ETHTornado.link(hasherContract, hasherInstance.address)
const tornado = await deployer.deploy(ETHTornado, verifier.address, ETH_AMOUNT, MERKLE_TREE_HEIGHT, accounts[0])
console.log('ETHTornado\'s address ', tornado.address)
})
}

View File

@ -1,6 +1,6 @@
/* global artifacts */
require('dotenv').config({ path: '../.env' })
const ERC20Mixer = artifacts.require('ERC20Mixer')
const ERC20Tornado = artifacts.require('ERC20Tornado')
const Verifier = artifacts.require('Verifier')
const hasherContract = artifacts.require('Hasher')
const ERC20Mock = artifacts.require('ERC20Mock')
@ -11,20 +11,20 @@ module.exports = function(deployer, network, accounts) {
const { MERKLE_TREE_HEIGHT, ERC20_TOKEN, TOKEN_AMOUNT } = process.env
const verifier = await Verifier.deployed()
const hasherInstance = await hasherContract.deployed()
await ERC20Mixer.link(hasherContract, hasherInstance.address)
await ERC20Tornado.link(hasherContract, hasherInstance.address)
let token = ERC20_TOKEN
if(token === '') {
const tokenInstance = await deployer.deploy(ERC20Mock)
token = tokenInstance.address
}
const mixer = await deployer.deploy(
ERC20Mixer,
const tornado = await deployer.deploy(
ERC20Tornado,
verifier.address,
TOKEN_AMOUNT,
MERKLE_TREE_HEIGHT,
accounts[0],
token,
)
console.log('ERC20Mixer\'s address ', mixer.address)
console.log('ERC20Tornado\'s address ', tornado.address)
})
}

View File

@ -20,7 +20,7 @@
"migrate:rinkeby": "npx truffle migrate --network rinkeby --reset",
"migrate:mainnet": "npx truffle migrate --network mainnet",
"eslint": "npx eslint --ignore-path .gitignore .",
"flat": "truffle-flattener contracts/ETHMixer.sol > ETHMixer_flat.sol contracts/ERC20Mixer.sol > ERC20Mixer_flat.sol"
"flat": "npx truffle-flattener contracts/ETHTornado.sol > ETHTornado_flat.sol && npx truffle-flattener contracts/ERC20Tornado.sol > ERC20Tornado_flat.sol"
},
"keywords": [],
"author": "",

View File

@ -8,7 +8,7 @@ const fs = require('fs')
const { toBN } = require('web3-utils')
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
const Mixer = artifacts.require('./ERC20Mixer.sol')
const Tornado = artifacts.require('./ERC20Tornado.sol')
const BadRecipient = artifacts.require('./BadRecipient.sol')
const Token = artifacts.require('./ERC20Mock.sol')
const USDTToken = artifacts.require('./IUSDT.sol')
@ -38,8 +38,8 @@ function generateDeposit() {
return deposit
}
contract('ERC20Mixer', accounts => {
let mixer
contract('ERC20Tornado', accounts => {
let tornado
let token
let usdtToken
let badRecipient
@ -64,7 +64,7 @@ contract('ERC20Mixer', accounts => {
null,
prefix,
)
mixer = await Mixer.deployed()
tornado = await Tornado.deployed()
if (ERC20_TOKEN) {
token = await Token.at(ERC20_TOKEN)
usdtToken = await USDTToken.at(ERC20_TOKEN)
@ -81,7 +81,7 @@ contract('ERC20Mixer', accounts => {
describe('#constructor', () => {
it('should initialize', async () => {
const tokenFromContract = await mixer.token()
const tokenFromContract = await tornado.token()
tokenFromContract.should.be.equal(token.address)
})
})
@ -89,9 +89,9 @@ contract('ERC20Mixer', accounts => {
describe('#deposit', () => {
it('should work', async () => {
const commitment = toFixedHex(43)
await token.approve(mixer.address, tokenDenomination)
await token.approve(tornado.address, tokenDenomination)
let { logs } = await mixer.deposit(commitment, { from: sender })
let { logs } = await tornado.deposit(commitment, { from: sender })
logs[0].event.should.be.equal('Deposit')
logs[0].args.commitment.should.be.equal(commitment)
@ -100,10 +100,10 @@ contract('ERC20Mixer', accounts => {
it('should not allow to send ether on deposit', async () => {
const commitment = toFixedHex(43)
await token.approve(mixer.address, tokenDenomination)
await token.approve(tornado.address, tokenDenomination)
let error = await mixer.deposit(commitment, { from: sender, value: 1e6 }).should.be.rejected
error.reason.should.be.equal('ETH value is supposed to be 0 for ERC20 mixer')
let error = await tornado.deposit(commitment, { from: sender, value: 1e6 }).should.be.rejected
error.reason.should.be.equal('ETH value is supposed to be 0 for ERC20 instance')
})
})
@ -115,11 +115,11 @@ contract('ERC20Mixer', accounts => {
await token.mint(user, tokenDenomination)
const balanceUserBefore = await token.balanceOf(user)
await token.approve(mixer.address, tokenDenomination, { from: user })
await token.approve(tornado.address, tokenDenomination, { from: user })
// Uncomment to measure gas usage
// let gas = await mixer.deposit.estimateGas(toBN(deposit.commitment.toString()), { from: user, gasPrice: '0' })
// let gas = await tornado.deposit.estimateGas(toBN(deposit.commitment.toString()), { from: user, gasPrice: '0' })
// console.log('deposit gas:', gas)
await mixer.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
await tornado.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
const balanceUserAfter = await token.balanceOf(user)
balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(tokenDenomination)))
@ -146,17 +146,17 @@ contract('ERC20Mixer', accounts => {
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
const { proof } = websnarkUtils.toSolidityInput(proofData)
const balanceMixerBefore = await token.balanceOf(mixer.address)
const balanceTornadoBefore = await token.balanceOf(tornado.address)
const balanceRelayerBefore = await token.balanceOf(relayer)
const balanceRecieverBefore = await token.balanceOf(toFixedHex(recipient, 20))
const ethBalanceOperatorBefore = await web3.eth.getBalance(operator)
const ethBalanceRecieverBefore = await web3.eth.getBalance(toFixedHex(recipient, 20))
const ethBalanceRelayerBefore = await web3.eth.getBalance(relayer)
let isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
let isSpent = await tornado.isSpent(toFixedHex(input.nullifierHash))
isSpent.should.be.equal(false)
// Uncomment to measure gas usage
// gas = await mixer.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// gas = await tornado.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// console.log('withdraw gas:', gas)
const args = [
toFixedHex(input.root),
@ -166,16 +166,16 @@ contract('ERC20Mixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const { logs } = await mixer.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const { logs } = await tornado.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const balanceMixerAfter = await token.balanceOf(mixer.address)
const balanceTornadoAfter = await token.balanceOf(tornado.address)
const balanceRelayerAfter = await token.balanceOf(relayer)
const ethBalanceOperatorAfter = await web3.eth.getBalance(operator)
const balanceRecieverAfter = await token.balanceOf(toFixedHex(recipient, 20))
const ethBalanceRecieverAfter = await web3.eth.getBalance(toFixedHex(recipient, 20))
const ethBalanceRelayerAfter = await web3.eth.getBalance(relayer)
const feeBN = toBN(fee.toString())
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(tokenDenomination)))
balanceTornadoAfter.should.be.eq.BN(toBN(balanceTornadoBefore).sub(toBN(tokenDenomination)))
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore).add(feeBN))
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(tokenDenomination).sub(feeBN)))
@ -187,7 +187,7 @@ contract('ERC20Mixer', accounts => {
logs[0].args.nullifierHash.should.be.equal(toFixedHex(input.nullifierHash))
logs[0].args.relayer.should.be.eq.BN(relayer)
logs[0].args.fee.should.be.eq.BN(feeBN)
isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
isSpent = await tornado.isSpent(toFixedHex(input.nullifierHash))
isSpent.should.be.equal(true)
})
@ -199,8 +199,8 @@ contract('ERC20Mixer', accounts => {
await token.mint(user, tokenDenomination)
const balanceUserBefore = await token.balanceOf(user)
await token.approve(mixer.address, tokenDenomination, { from: user })
await mixer.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
await token.approve(tornado.address, tokenDenomination, { from: user })
await tornado.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
const balanceUserAfter = await token.balanceOf(user)
balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(tokenDenomination)))
@ -227,14 +227,14 @@ contract('ERC20Mixer', accounts => {
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
const { proof } = websnarkUtils.toSolidityInput(proofData)
const balanceMixerBefore = await token.balanceOf(mixer.address)
const balanceTornadoBefore = await token.balanceOf(tornado.address)
const balanceRelayerBefore = await token.balanceOf(relayer)
const balanceRecieverBefore = await token.balanceOf(toFixedHex(recipient, 20))
const ethBalanceOperatorBefore = await web3.eth.getBalance(operator)
const ethBalanceRecieverBefore = await web3.eth.getBalance(toFixedHex(recipient, 20))
const ethBalanceRelayerBefore = await web3.eth.getBalance(relayer)
let isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
let isSpent = await tornado.isSpent(toFixedHex(input.nullifierHash))
isSpent.should.be.equal(false)
const args = [
@ -245,16 +245,16 @@ contract('ERC20Mixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const { logs } = await mixer.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const { logs } = await tornado.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const balanceMixerAfter = await token.balanceOf(mixer.address)
const balanceTornadoAfter = await token.balanceOf(tornado.address)
const balanceRelayerAfter = await token.balanceOf(relayer)
const ethBalanceOperatorAfter = await web3.eth.getBalance(operator)
const balanceRecieverAfter = await token.balanceOf(toFixedHex(recipient, 20))
const ethBalanceRecieverAfter = await web3.eth.getBalance(toFixedHex(recipient, 20))
const ethBalanceRelayerAfter = await web3.eth.getBalance(relayer)
const feeBN = toBN(fee.toString())
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(tokenDenomination)))
balanceTornadoAfter.should.be.eq.BN(toBN(balanceTornadoBefore).sub(toBN(tokenDenomination)))
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore).add(feeBN))
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(tokenDenomination).sub(feeBN)))
@ -266,7 +266,7 @@ contract('ERC20Mixer', accounts => {
logs[0].args.nullifierHash.should.be.equal(toFixedHex(input.nullifierHash))
logs[0].args.relayer.should.be.eq.BN(relayer)
logs[0].args.fee.should.be.eq.BN(feeBN)
isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
isSpent = await tornado.isSpent(toFixedHex(input.nullifierHash))
isSpent.should.be.equal(true)
})
@ -275,8 +275,8 @@ contract('ERC20Mixer', accounts => {
const user = accounts[4]
await tree.insert(deposit.commitment)
await token.mint(user, tokenDenomination)
await token.approve(mixer.address, tokenDenomination, { from: user })
await mixer.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
await token.approve(tornado.address, tokenDenomination, { from: user })
await tornado.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
const { root, path_elements, path_index } = await tree.path(0)
@ -309,11 +309,11 @@ contract('ERC20Mixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
let { reason } = await mixer.withdraw(proof, ...args, { value: 1, from: relayer, gasPrice: '0' }).should.be.rejected
let { reason } = await tornado.withdraw(proof, ...args, { value: 1, from: relayer, gasPrice: '0' }).should.be.rejected
reason.should.be.equal('Incorrect refund amount received by the contract')
;({ reason } = await mixer.withdraw(proof, ...args, { value: toBN(refund).mul(toBN(2)), from: relayer, gasPrice: '0' }).should.be.rejected)
;({ reason } = await tornado.withdraw(proof, ...args, { value: toBN(refund).mul(toBN(2)), from: relayer, gasPrice: '0' }).should.be.rejected)
reason.should.be.equal('Incorrect refund amount received by the contract')
})
@ -335,11 +335,11 @@ contract('ERC20Mixer', accounts => {
const balanceUserBefore = await usdtToken.balanceOf(user)
console.log('balanceUserBefore', balanceUserBefore.toString())
await usdtToken.approve(mixer.address, tokenDenomination, { from: user })
await usdtToken.approve(tornado.address, tokenDenomination, { from: user })
console.log('approve done')
const allowanceUser = await usdtToken.allowance(user, mixer.address)
const allowanceUser = await usdtToken.allowance(user, tornado.address)
console.log('allowanceUser', allowanceUser.toString())
await mixer.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
await tornado.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
console.log('deposit done')
const balanceUserAfter = await usdtToken.balanceOf(user)
@ -368,16 +368,16 @@ contract('ERC20Mixer', accounts => {
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
const { proof } = websnarkUtils.toSolidityInput(proofData)
const balanceMixerBefore = await usdtToken.balanceOf(mixer.address)
const balanceTornadoBefore = await usdtToken.balanceOf(tornado.address)
const balanceRelayerBefore = await usdtToken.balanceOf(relayer)
const ethBalanceOperatorBefore = await web3.eth.getBalance(operator)
const balanceRecieverBefore = await usdtToken.balanceOf(toFixedHex(recipient, 20))
const ethBalanceRecieverBefore = await web3.eth.getBalance(toFixedHex(recipient, 20))
let isSpent = await mixer.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
let isSpent = await tornado.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
isSpent.should.be.equal(false)
// Uncomment to measure gas usage
// gas = await mixer.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// gas = await tornado.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// console.log('withdraw gas:', gas)
const args = [
toFixedHex(input.root),
@ -387,15 +387,15 @@ contract('ERC20Mixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const { logs } = await mixer.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const { logs } = await tornado.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const balanceMixerAfter = await usdtToken.balanceOf(mixer.address)
const balanceTornadoAfter = await usdtToken.balanceOf(tornado.address)
const balanceRelayerAfter = await usdtToken.balanceOf(relayer)
const ethBalanceOperatorAfter = await web3.eth.getBalance(operator)
const balanceRecieverAfter = await usdtToken.balanceOf(toFixedHex(recipient, 20))
const ethBalanceRecieverAfter = await web3.eth.getBalance(toFixedHex(recipient, 20))
const feeBN = toBN(fee.toString())
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(tokenDenomination)))
balanceTornadoAfter.should.be.eq.BN(toBN(balanceTornadoBefore).sub(toBN(tokenDenomination)))
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore))
ethBalanceOperatorAfter.should.be.eq.BN(toBN(ethBalanceOperatorBefore).add(feeBN))
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(tokenDenomination)))
@ -406,7 +406,7 @@ contract('ERC20Mixer', accounts => {
logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString()))
logs[0].args.relayer.should.be.eq.BN(operator)
logs[0].args.fee.should.be.eq.BN(feeBN)
isSpent = await mixer.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
isSpent = await tornado.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
isSpent.should.be.equal(true)
})
it.skip('should work with REAL DAI', async () => {
@ -426,9 +426,9 @@ contract('ERC20Mixer', accounts => {
const balanceUserBefore = await token.balanceOf(user)
console.log('balanceUserBefore', balanceUserBefore.toString())
await token.approve(mixer.address, tokenDenomination, { from: user })
await token.approve(tornado.address, tokenDenomination, { from: user })
console.log('approve done')
await mixer.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
await tornado.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
console.log('deposit done')
const balanceUserAfter = await token.balanceOf(user)
@ -457,16 +457,16 @@ contract('ERC20Mixer', accounts => {
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
const { proof } = websnarkUtils.toSolidityInput(proofData)
const balanceMixerBefore = await token.balanceOf(mixer.address)
const balanceTornadoBefore = await token.balanceOf(tornado.address)
const balanceRelayerBefore = await token.balanceOf(relayer)
const ethBalanceOperatorBefore = await web3.eth.getBalance(operator)
const balanceRecieverBefore = await token.balanceOf(toFixedHex(recipient, 20))
const ethBalanceRecieverBefore = await web3.eth.getBalance(toFixedHex(recipient, 20))
let isSpent = await mixer.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
let isSpent = await tornado.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
isSpent.should.be.equal(false)
// Uncomment to measure gas usage
// gas = await mixer.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// gas = await tornado.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// console.log('withdraw gas:', gas)
const args = [
toFixedHex(input.root),
@ -476,16 +476,16 @@ contract('ERC20Mixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const { logs } = await mixer.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
const { logs } = await tornado.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
console.log('withdraw done')
const balanceMixerAfter = await token.balanceOf(mixer.address)
const balanceTornadoAfter = await token.balanceOf(tornado.address)
const balanceRelayerAfter = await token.balanceOf(relayer)
const ethBalanceOperatorAfter = await web3.eth.getBalance(operator)
const balanceRecieverAfter = await token.balanceOf(toFixedHex(recipient, 20))
const ethBalanceRecieverAfter = await web3.eth.getBalance(toFixedHex(recipient, 20))
const feeBN = toBN(fee.toString())
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(tokenDenomination)))
balanceTornadoAfter.should.be.eq.BN(toBN(balanceTornadoBefore).sub(toBN(tokenDenomination)))
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore))
ethBalanceOperatorAfter.should.be.eq.BN(toBN(ethBalanceOperatorBefore).add(feeBN))
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(tokenDenomination)))
@ -496,7 +496,7 @@ contract('ERC20Mixer', accounts => {
logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString()))
logs[0].args.relayer.should.be.eq.BN(operator)
logs[0].args.fee.should.be.eq.BN(feeBN)
isSpent = await mixer.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
isSpent = await tornado.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
isSpent.should.be.equal(true)
})
})

View File

@ -8,7 +8,7 @@ const fs = require('fs')
const { toBN, randomHex } = require('web3-utils')
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
const Mixer = artifacts.require('./ETHMixer.sol')
const Tornado = artifacts.require('./ETHTornado.sol')
const { ETH_AMOUNT, MERKLE_TREE_HEIGHT } = process.env
const websnarkUtils = require('websnark/src/utils')
@ -51,8 +51,8 @@ function snarkVerify(proof) {
return snarkjs['groth'].isValid(verification_key, proof, proof.publicSignals)
}
contract('ETHMixer', accounts => {
let mixer
contract('ETHTornado', accounts => {
let tornado
const sender = accounts[0]
const operator = accounts[0]
const levels = MERKLE_TREE_HEIGHT || 16
@ -74,7 +74,7 @@ contract('ETHMixer', accounts => {
null,
prefix,
)
mixer = await Mixer.deployed()
tornado = await Tornado.deployed()
snapshotId = await takeSnapshot()
groth16 = await buildGroth16()
circuit = require('../build/circuits/withdraw.json')
@ -83,7 +83,7 @@ contract('ETHMixer', accounts => {
describe('#constructor', () => {
it('should initialize', async () => {
const etherDenomination = await mixer.denomination()
const etherDenomination = await tornado.denomination()
etherDenomination.should.be.eq.BN(toBN(value))
})
})
@ -91,14 +91,14 @@ contract('ETHMixer', accounts => {
describe('#deposit', () => {
it('should emit event', async () => {
let commitment = toFixedHex(42)
let { logs } = await mixer.deposit(commitment, { value, from: sender })
let { logs } = await tornado.deposit(commitment, { value, from: sender })
logs[0].event.should.be.equal('Deposit')
logs[0].args.commitment.should.be.equal(commitment)
logs[0].args.leafIndex.should.be.eq.BN(0)
commitment = toFixedHex(12);
({ logs } = await mixer.deposit(commitment, { value, from: accounts[2] }))
({ logs } = await tornado.deposit(commitment, { value, from: accounts[2] }))
logs[0].event.should.be.equal('Deposit')
logs[0].args.commitment.should.be.equal(commitment)
@ -107,8 +107,8 @@ contract('ETHMixer', accounts => {
it('should throw if there is a such commitment', async () => {
const commitment = toFixedHex(42)
await mixer.deposit(commitment, { value, from: sender }).should.be.fulfilled
const error = await mixer.deposit(commitment, { value, from: sender }).should.be.rejected
await tornado.deposit(commitment, { value, from: sender }).should.be.fulfilled
const error = await tornado.deposit(commitment, { value, from: sender }).should.be.rejected
error.reason.should.be.equal('The commitment has been submitted')
})
})
@ -166,9 +166,9 @@ contract('ETHMixer', accounts => {
const balanceUserBefore = await web3.eth.getBalance(user)
// Uncomment to measure gas usage
// let gas = await mixer.deposit.estimateGas(toBN(deposit.commitment.toString()), { value, from: user, gasPrice: '0' })
// let gas = await tornado.deposit.estimateGas(toBN(deposit.commitment.toString()), { value, from: user, gasPrice: '0' })
// console.log('deposit gas:', gas)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: user, gasPrice: '0' })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: user, gasPrice: '0' })
const balanceUserAfter = await web3.eth.getBalance(user)
balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(value)))
@ -196,15 +196,15 @@ contract('ETHMixer', accounts => {
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
const { proof } = websnarkUtils.toSolidityInput(proofData)
const balanceMixerBefore = await web3.eth.getBalance(mixer.address)
const balanceTornadoBefore = await web3.eth.getBalance(tornado.address)
const balanceRelayerBefore = await web3.eth.getBalance(relayer)
const balanceOperatorBefore = await web3.eth.getBalance(operator)
const balanceRecieverBefore = await web3.eth.getBalance(toFixedHex(recipient, 20))
let isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
let isSpent = await tornado.isSpent(toFixedHex(input.nullifierHash))
isSpent.should.be.equal(false)
// Uncomment to measure gas usage
// gas = await mixer.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// gas = await tornado.withdraw.estimateGas(proof, publicSignals, { from: relayer, gasPrice: '0' })
// console.log('withdraw gas:', gas)
const args = [
toFixedHex(input.root),
@ -214,14 +214,14 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const { logs } = await mixer.withdraw(proof, ...args, { from: relayer, gasPrice: '0' })
const { logs } = await tornado.withdraw(proof, ...args, { from: relayer, gasPrice: '0' })
const balanceMixerAfter = await web3.eth.getBalance(mixer.address)
const balanceTornadoAfter = await web3.eth.getBalance(tornado.address)
const balanceRelayerAfter = await web3.eth.getBalance(relayer)
const balanceOperatorAfter = await web3.eth.getBalance(operator)
const balanceRecieverAfter = await web3.eth.getBalance(toFixedHex(recipient, 20))
const feeBN = toBN(fee.toString())
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(value)))
balanceTornadoAfter.should.be.eq.BN(toBN(balanceTornadoBefore).sub(toBN(value)))
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore))
balanceOperatorAfter.should.be.eq.BN(toBN(balanceOperatorBefore).add(feeBN))
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(value)).sub(feeBN))
@ -231,14 +231,14 @@ contract('ETHMixer', accounts => {
logs[0].args.nullifierHash.should.be.equal(toFixedHex(input.nullifierHash))
logs[0].args.relayer.should.be.eq.BN(operator)
logs[0].args.fee.should.be.eq.BN(feeBN)
isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
isSpent = await tornado.isSpent(toFixedHex(input.nullifierHash))
isSpent.should.be.equal(true)
})
it('should prevent double spend', async () => {
const deposit = generateDeposit()
await tree.insert(deposit.commitment)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: sender })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: sender })
const { root, path_elements, path_index } = await tree.path(0)
@ -264,15 +264,15 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
await mixer.withdraw(proof, ...args, { from: relayer }).should.be.fulfilled
const error = await mixer.withdraw(proof, ...args, { from: relayer }).should.be.rejected
await tornado.withdraw(proof, ...args, { from: relayer }).should.be.fulfilled
const error = await tornado.withdraw(proof, ...args, { from: relayer }).should.be.rejected
error.reason.should.be.equal('The note has been already spent')
})
it('should prevent double spend with overflow', async () => {
const deposit = generateDeposit()
await tree.insert(deposit.commitment)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: sender })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: sender })
const { root, path_elements, path_index } = await tree.path(0)
@ -298,14 +298,14 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const error = await mixer.withdraw(proof, ...args, { from: relayer }).should.be.rejected
const error = await tornado.withdraw(proof, ...args, { from: relayer }).should.be.rejected
error.reason.should.be.equal('verifier-gte-snark-scalar-field')
})
it('fee should be less or equal transfer value', async () => {
const deposit = generateDeposit()
await tree.insert(deposit.commitment)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: sender })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: sender })
const { root, path_elements, path_index } = await tree.path(0)
const largeFee = bigInt(value).add(bigInt(1))
@ -332,14 +332,14 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const error = await mixer.withdraw(proof, ...args, { from: relayer }).should.be.rejected
const error = await tornado.withdraw(proof, ...args, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Fee exceeds transfer value')
})
it('should throw for corrupted merkle tree root', async () => {
const deposit = generateDeposit()
await tree.insert(deposit.commitment)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: sender })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: sender })
const { root, path_elements, path_index } = await tree.path(0)
@ -367,14 +367,14 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const error = await mixer.withdraw(proof, ...args, { from: relayer }).should.be.rejected
const error = await tornado.withdraw(proof, ...args, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Cannot find your merkle root')
})
it('should reject with tampered public inputs', async () => {
const deposit = generateDeposit()
await tree.insert(deposit.commitment)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: sender })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: sender })
let { root, path_elements, path_index } = await tree.path(0)
@ -412,7 +412,7 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
let error = await mixer.withdraw(proof, ...incorrectArgs, { from: relayer }).should.be.rejected
let error = await tornado.withdraw(proof, ...incorrectArgs, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Invalid withdraw proof')
// fee
@ -424,7 +424,7 @@ contract('ETHMixer', accounts => {
toFixedHex('0x000000000000000000000000000000000000000000000000015345785d8a0000'),
toFixedHex(input.refund)
]
error = await mixer.withdraw(proof, ...incorrectArgs, { from: relayer }).should.be.rejected
error = await tornado.withdraw(proof, ...incorrectArgs, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Invalid withdraw proof')
// nullifier
@ -436,21 +436,21 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
error = await mixer.withdraw(proof, ...incorrectArgs, { from: relayer }).should.be.rejected
error = await tornado.withdraw(proof, ...incorrectArgs, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Invalid withdraw proof')
// proof itself
proof = '0xbeef' + proof.substr(6)
await mixer.withdraw(proof, ...args, { from: relayer }).should.be.rejected
await tornado.withdraw(proof, ...args, { from: relayer }).should.be.rejected
// should work with original values
await mixer.withdraw(originalProof, ...args, { from: relayer }).should.be.fulfilled
await tornado.withdraw(originalProof, ...args, { from: relayer }).should.be.fulfilled
})
it('should reject with non zero refund', async () => {
const deposit = generateDeposit()
await tree.insert(deposit.commitment)
await mixer.deposit(toFixedHex(deposit.commitment), { value, from: sender })
await tornado.deposit(toFixedHex(deposit.commitment), { value, from: sender })
const { root, path_elements, path_index } = await tree.path(0)
@ -478,29 +478,29 @@ contract('ETHMixer', accounts => {
toFixedHex(input.fee),
toFixedHex(input.refund)
]
const error = await mixer.withdraw(proof, ...args, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Refund value is supposed to be zero for ETH mixer')
const error = await tornado.withdraw(proof, ...args, { from: relayer }).should.be.rejected
error.reason.should.be.equal('Refund value is supposed to be zero for ETH instance')
})
})
describe('#changeOperator', () => {
it('should work', async () => {
let operator = await mixer.operator()
let operator = await tornado.operator()
operator.should.be.equal(sender)
const newOperator = accounts[7]
await mixer.changeOperator(newOperator).should.be.fulfilled
await tornado.changeOperator(newOperator).should.be.fulfilled
operator = await mixer.operator()
operator = await tornado.operator()
operator.should.be.equal(newOperator)
})
it('cannot change from different address', async () => {
let operator = await mixer.operator()
let operator = await tornado.operator()
operator.should.be.equal(sender)
const newOperator = accounts[7]
const error = await mixer.changeOperator(newOperator, { from: accounts[7] }).should.be.rejected
const error = await tornado.changeOperator(newOperator, { from: accounts[7] }).should.be.rejected
error.reason.should.be.equal('Only operator can call this function.')
})
@ -508,22 +508,22 @@ contract('ETHMixer', accounts => {
describe('#updateVerifier', () => {
it('should work', async () => {
let operator = await mixer.operator()
let operator = await tornado.operator()
operator.should.be.equal(sender)
const newVerifier = accounts[7]
await mixer.updateVerifier(newVerifier).should.be.fulfilled
await tornado.updateVerifier(newVerifier).should.be.fulfilled
const verifier = await mixer.verifier()
const verifier = await tornado.verifier()
verifier.should.be.equal(newVerifier)
})
it('cannot change from different address', async () => {
let operator = await mixer.operator()
let operator = await tornado.operator()
operator.should.be.equal(sender)
const newVerifier = accounts[7]
const error = await mixer.updateVerifier(newVerifier, { from: accounts[7] }).should.be.rejected
const error = await tornado.updateVerifier(newVerifier, { from: accounts[7] }).should.be.rejected
error.reason.should.be.equal('Only operator can call this function.')
})
@ -535,8 +535,8 @@ contract('ETHMixer', accounts => {
const deposit2 = generateDeposit()
await tree.insert(deposit1.commitment)
await tree.insert(deposit2.commitment)
await mixer.deposit(toFixedHex(deposit1.commitment), { value, gasPrice: '0' })
await mixer.deposit(toFixedHex(deposit2.commitment), { value, gasPrice: '0' })
await tornado.deposit(toFixedHex(deposit1.commitment), { value, gasPrice: '0' })
await tornado.deposit(toFixedHex(deposit2.commitment), { value, gasPrice: '0' })
const { root, path_elements, path_index } = await tree.path(1)
@ -570,11 +570,11 @@ contract('ETHMixer', accounts => {
toFixedHex(input.refund)
]
await mixer.withdraw(proof, ...args, { from: relayer, gasPrice: '0' })
await tornado.withdraw(proof, ...args, { from: relayer, gasPrice: '0' })
const nullifierHash1 = toFixedHex(pedersenHash(deposit1.nullifier.leInt2Buff(31)))
const nullifierHash2 = toFixedHex(pedersenHash(deposit2.nullifier.leInt2Buff(31)))
const spentArray = await mixer.isSpentArray([nullifierHash1, nullifierHash2])
const spentArray = await tornado.isSpentArray([nullifierHash1, nullifierHash2])
spentArray.should.be.deep.equal([false, true])
})
})