mirror of
https://github.com/tornadocash/tornado-core.git
synced 2024-11-22 01:37:07 +01:00
additional eth for the recipient
This commit is contained in:
parent
0f5a5df522
commit
9f33aadd9d
@ -1,6 +1,7 @@
|
|||||||
MERKLE_TREE_HEIGHT=16
|
MERKLE_TREE_HEIGHT=16
|
||||||
# in wei
|
# in wei
|
||||||
AMOUNT=1000000000000000000
|
ETH_AMOUNT=100000000000000000
|
||||||
|
TOKEN_AMOUNT=100000000000000000
|
||||||
EMPTY_ELEMENT=1337
|
EMPTY_ELEMENT=1337
|
||||||
PRIVATE_KEY=
|
PRIVATE_KEY=
|
||||||
ERC20_TOKEN=
|
ERC20_TOKEN=
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -94,3 +94,5 @@ typings/
|
|||||||
# DynamoDB Local files
|
# DynamoDB Local files
|
||||||
.dynamodb/
|
.dynamodb/
|
||||||
|
|
||||||
|
ERC20Mixer_flat.sol
|
||||||
|
ETHMixer_flat.sol
|
||||||
|
13
README.md
13
README.md
@ -41,6 +41,19 @@ spent since it has the same nullifier and it will prevent you from withdrawing y
|
|||||||
1. `npx http-server` - serve current dir, you can use any other http server
|
1. `npx http-server` - serve current dir, you can use any other http server
|
||||||
1. Open `localhost:8080`
|
1. Open `localhost:8080`
|
||||||
|
|
||||||
|
## Deploy ETH Tornado Cash
|
||||||
|
1. `cp .env.example .env`
|
||||||
|
1. Tune all necessary params
|
||||||
|
1. `npx truffle migrate --f 2 --to 4`
|
||||||
|
|
||||||
|
## Deploy ERC20 Tornado Cash
|
||||||
|
1. `cp .env.example .env`
|
||||||
|
1. Tune all necessary params
|
||||||
|
1. `npx truffle migrate --f 2 --to 3`
|
||||||
|
1. `npx truffle migrate --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`).
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
Special thanks to @barryWhiteHat and @kobigurk for valuable input,
|
Special thanks to @barryWhiteHat and @kobigurk for valuable input,
|
||||||
|
8
cli.js
8
cli.js
@ -13,7 +13,7 @@ const buildGroth16 = require('websnark/src/groth16')
|
|||||||
const websnarkUtils = require('websnark/src/utils')
|
const websnarkUtils = require('websnark/src/utils')
|
||||||
|
|
||||||
let web3, mixer, circuit, proving_key, groth16
|
let web3, mixer, circuit, proving_key, groth16
|
||||||
let MERKLE_TREE_HEIGHT, AMOUNT, EMPTY_ELEMENT
|
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, EMPTY_ELEMENT
|
||||||
const inBrowser = (typeof window !== 'undefined')
|
const inBrowser = (typeof window !== 'undefined')
|
||||||
|
|
||||||
const rbigint = (nbytes) => snarkjs.bigInt.leBuff2int(crypto.randomBytes(nbytes))
|
const rbigint = (nbytes) => snarkjs.bigInt.leBuff2int(crypto.randomBytes(nbytes))
|
||||||
@ -30,7 +30,7 @@ async function deposit() {
|
|||||||
const deposit = createDeposit(rbigint(31), rbigint(31))
|
const deposit = createDeposit(rbigint(31), rbigint(31))
|
||||||
|
|
||||||
console.log('Submitting deposit transaction')
|
console.log('Submitting deposit transaction')
|
||||||
await mixer.methods.deposit('0x' + deposit.commitment.toString(16)).send({ value: AMOUNT, from: (await web3.eth.getAccounts())[0], gas:1e6 })
|
await mixer.methods.deposit('0x' + deposit.commitment.toString(16)).send({ value: ETH_AMOUNT, from: (await web3.eth.getAccounts())[0], gas:1e6 })
|
||||||
|
|
||||||
const note = '0x' + deposit.preimage.toString('hex')
|
const note = '0x' + deposit.preimage.toString('hex')
|
||||||
console.log('Your note:', note)
|
console.log('Your note:', note)
|
||||||
@ -103,7 +103,7 @@ async function init() {
|
|||||||
circuit = await (await fetch('build/circuits/withdraw.json')).json()
|
circuit = await (await fetch('build/circuits/withdraw.json')).json()
|
||||||
proving_key = await (await fetch('build/circuits/withdraw_proving_key.bin')).arrayBuffer()
|
proving_key = await (await fetch('build/circuits/withdraw_proving_key.bin')).arrayBuffer()
|
||||||
MERKLE_TREE_HEIGHT = 16
|
MERKLE_TREE_HEIGHT = 16
|
||||||
AMOUNT = 1e18
|
ETH_AMOUNT = 1e18
|
||||||
EMPTY_ELEMENT = 0
|
EMPTY_ELEMENT = 0
|
||||||
} else {
|
} else {
|
||||||
web3 = new Web3('http://localhost:8545', null, { transactionConfirmationBlocks: 1 })
|
web3 = new Web3('http://localhost:8545', null, { transactionConfirmationBlocks: 1 })
|
||||||
@ -112,7 +112,7 @@ async function init() {
|
|||||||
proving_key = fs.readFileSync('build/circuits/withdraw_proving_key.bin').buffer
|
proving_key = fs.readFileSync('build/circuits/withdraw_proving_key.bin').buffer
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT
|
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT
|
||||||
AMOUNT = process.env.AMOUNT
|
ETH_AMOUNT = process.env.ETH_AMOUNT
|
||||||
EMPTY_ELEMENT = process.env.EMPTY_ELEMENT
|
EMPTY_ELEMENT = process.env.EMPTY_ELEMENT
|
||||||
}
|
}
|
||||||
groth16 = await buildGroth16()
|
groth16 = await buildGroth16()
|
||||||
|
@ -16,38 +16,61 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|||||||
|
|
||||||
contract ERC20Mixer is Mixer {
|
contract ERC20Mixer is Mixer {
|
||||||
IERC20 public token;
|
IERC20 public token;
|
||||||
|
// mixed token amount
|
||||||
|
uint256 public tokenDenomination;
|
||||||
|
// ether value to cover network fee (for relayer) and to have some ETH on a brand new address
|
||||||
|
uint256 public etherFeeDenomination;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
address _verifier,
|
address _verifier,
|
||||||
uint256 _transferValue,
|
uint256 _etherFeeDenomination,
|
||||||
uint8 _merkleTreeHeight,
|
uint8 _merkleTreeHeight,
|
||||||
uint256 _emptyElement,
|
uint256 _emptyElement,
|
||||||
address payable _operator,
|
address payable _operator,
|
||||||
IERC20 _token
|
IERC20 _token,
|
||||||
) Mixer(_verifier, _transferValue, _merkleTreeHeight, _emptyElement, _operator) public {
|
uint256 _tokenDenomination
|
||||||
|
) Mixer(_verifier, _merkleTreeHeight, _emptyElement, _operator) public {
|
||||||
token = _token;
|
token = _token;
|
||||||
|
tokenDenomination = _tokenDenomination;
|
||||||
|
etherFeeDenomination = _etherFeeDenomination;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deposit(uint256 commitment) public {
|
/**
|
||||||
require(token.transferFrom(msg.sender, address(this), transferValue), "Approve before using");
|
@dev Deposit funds into the mixer. The caller must send ETH value equal to `etherFeeDenomination` of this mixer.
|
||||||
|
The caller also has to have at least `tokenDenomination` amount approved for the mixer.
|
||||||
|
@param commitment the note commitment, which is PedersenHash(nullifier + secret)
|
||||||
|
*/
|
||||||
|
function deposit(uint256 commitment) public payable {
|
||||||
|
require(msg.value == etherFeeDenomination, "Please send `etherFeeDenomination` ETH along with transaction");
|
||||||
|
require(token.transferFrom(msg.sender, address(this), tokenDenomination), "Approve before using");
|
||||||
_deposit(commitment);
|
_deposit(commitment);
|
||||||
|
|
||||||
emit Deposit(commitment, next_index - 1, block.timestamp);
|
emit Deposit(commitment, next_index - 1, block.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@dev Withdraw deposit from the mixer. `a`, `b`, and `c` are zkSNARK proof data, and input is an array of circuit public inputs
|
||||||
|
`input` array consists of:
|
||||||
|
- merkle root of all deposits in the mixer
|
||||||
|
- hash of unique deposit nullifier to prevent double spends
|
||||||
|
- the receiver of funds
|
||||||
|
- optional fee that goes to the transaction sender (usually a relay)
|
||||||
|
*/
|
||||||
function withdraw(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[4] memory input) public {
|
function withdraw(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[4] memory input) public {
|
||||||
_withdraw(a, b, c, input);
|
_withdraw(a, b, c, input);
|
||||||
address receiver = address(input[2]);
|
address payable receiver = address(input[2]);
|
||||||
uint256 fee = input[3];
|
uint256 fee = input[3];
|
||||||
uint256 nullifierHash = input[1];
|
uint256 nullifierHash = input[1];
|
||||||
|
|
||||||
require(fee < transferValue, "Fee exceeds transfer value");
|
require(fee < etherFeeDenomination, "Fee exceeds transfer value");
|
||||||
token.transfer(receiver, transferValue - fee);
|
receiver.transfer(etherFeeDenomination - fee);
|
||||||
|
|
||||||
if (fee > 0) {
|
if (fee > 0) {
|
||||||
token.transfer(operator, fee);
|
operator.transfer(fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token.transfer(receiver, tokenDenomination);
|
||||||
|
|
||||||
emit Withdraw(receiver, nullifierHash, fee);
|
emit Withdraw(receiver, nullifierHash, fee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,30 +14,45 @@ pragma solidity ^0.5.8;
|
|||||||
import "./Mixer.sol";
|
import "./Mixer.sol";
|
||||||
|
|
||||||
contract ETHMixer is Mixer {
|
contract ETHMixer is Mixer {
|
||||||
|
uint256 public etherDenomination;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
address _verifier,
|
address _verifier,
|
||||||
uint256 _transferValue,
|
uint256 _etherDenomination,
|
||||||
uint8 _merkleTreeHeight,
|
uint8 _merkleTreeHeight,
|
||||||
uint256 _emptyElement,
|
uint256 _emptyElement,
|
||||||
address payable _operator
|
address payable _operator
|
||||||
) Mixer(_verifier, _transferValue, _merkleTreeHeight, _emptyElement, _operator) public {}
|
) Mixer(_verifier, _merkleTreeHeight, _emptyElement, _operator) public {
|
||||||
|
etherDenomination = _etherDenomination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@dev Deposit funds into mixer. The caller must send value equal to `etherDenomination` of this mixer.
|
||||||
|
@param commitment the note commitment, which is PedersenHash(nullifier + secret)
|
||||||
|
*/
|
||||||
function deposit(uint256 commitment) public payable {
|
function deposit(uint256 commitment) public payable {
|
||||||
require(msg.value == transferValue, "Please send `transferValue` ETH along with transaction");
|
require(msg.value == etherDenomination, "Please send `etherDenomination` ETH along with transaction");
|
||||||
_deposit(commitment);
|
_deposit(commitment);
|
||||||
|
|
||||||
emit Deposit(commitment, next_index - 1, block.timestamp);
|
emit Deposit(commitment, next_index - 1, block.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@dev Withdraw deposit from the mixer. `a`, `b`, and `c` are zkSNARK proof data, and input is an array of circuit public inputs
|
||||||
|
`input` array consists of:
|
||||||
|
- merkle root of all deposits in the mixer
|
||||||
|
- hash of unique deposit nullifier to prevent double spends
|
||||||
|
- the receiver of funds
|
||||||
|
- optional fee that goes to the transaction sender (usually a relay)
|
||||||
|
*/
|
||||||
function withdraw(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[4] memory input) public {
|
function withdraw(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[4] memory input) public {
|
||||||
_withdraw(a, b, c, input);
|
_withdraw(a, b, c, input);
|
||||||
address payable receiver = address(input[2]);
|
address payable receiver = address(input[2]);
|
||||||
uint256 fee = input[3];
|
uint256 fee = input[3];
|
||||||
uint256 nullifierHash = input[1];
|
uint256 nullifierHash = input[1];
|
||||||
|
|
||||||
require(fee < transferValue, "Fee exceeds transfer value");
|
require(fee < etherDenomination, "Fee exceeds transfer value");
|
||||||
receiver.transfer(transferValue - fee);
|
receiver.transfer(etherDenomination - fee);
|
||||||
if (fee > 0) {
|
if (fee > 0) {
|
||||||
operator.transfer(fee);
|
operator.transfer(fee);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ contract IVerifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contract Mixer is MerkleTreeWithHistory {
|
contract Mixer is MerkleTreeWithHistory {
|
||||||
uint256 public transferValue;
|
|
||||||
bool public isDepositsEnabled = true;
|
bool public isDepositsEnabled = true;
|
||||||
// operator can disable new deposits in case of emergency
|
// operator can disable new deposits in case of emergency
|
||||||
// it also receives a relayer fee
|
// it also receives a relayer fee
|
||||||
@ -34,24 +33,20 @@ contract Mixer is MerkleTreeWithHistory {
|
|||||||
/**
|
/**
|
||||||
@dev The constructor
|
@dev The constructor
|
||||||
@param _verifier the address of SNARK verifier for this contract
|
@param _verifier the address of SNARK verifier for this contract
|
||||||
@param _transferValue the value for all deposits in this contract in wei
|
@param _merkleTreeHeight the height of deposits' Merkle Tree
|
||||||
|
@param _emptyElement default element of the deposits' Merkle Tree
|
||||||
|
@param _operator operator address (see operator above)
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
address _verifier,
|
address _verifier,
|
||||||
uint256 _transferValue,
|
|
||||||
uint8 _merkleTreeHeight,
|
uint8 _merkleTreeHeight,
|
||||||
uint256 _emptyElement,
|
uint256 _emptyElement,
|
||||||
address payable _operator
|
address payable _operator
|
||||||
) MerkleTreeWithHistory(_merkleTreeHeight, _emptyElement) public {
|
) MerkleTreeWithHistory(_merkleTreeHeight, _emptyElement) public {
|
||||||
verifier = IVerifier(_verifier);
|
verifier = IVerifier(_verifier);
|
||||||
transferValue = _transferValue;
|
|
||||||
operator = _operator;
|
operator = _operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@dev Deposit funds into mixer. The caller must send value equal to `transferValue` of this mixer.
|
|
||||||
@param commitment the note commitment, which is PedersenHash(nullifier + secret)
|
|
||||||
*/
|
|
||||||
function _deposit(uint256 commitment) internal {
|
function _deposit(uint256 commitment) internal {
|
||||||
require(isDepositsEnabled, "deposits disabled");
|
require(isDepositsEnabled, "deposits disabled");
|
||||||
require(!commitments[commitment], "The commitment has been submitted");
|
require(!commitments[commitment], "The commitment has been submitted");
|
||||||
@ -59,14 +54,6 @@ contract Mixer is MerkleTreeWithHistory {
|
|||||||
commitments[commitment] = true;
|
commitments[commitment] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@dev Withdraw deposit from the mixer. `a`, `b`, and `c` are zkSNARK proof data, and input is an array of circuit public inputs
|
|
||||||
`input` array consists of:
|
|
||||||
- merkle root of all deposits in the mixer
|
|
||||||
- hash of unique deposit nullifier to prevent double spends
|
|
||||||
- the receiver of funds
|
|
||||||
- optional fee that goes to the transaction sender (usually a relay)
|
|
||||||
*/
|
|
||||||
function _withdraw(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[4] memory input) internal {
|
function _withdraw(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[4] memory input) internal {
|
||||||
uint256 root = input[0];
|
uint256 root = input[0];
|
||||||
uint256 nullifierHash = input[1];
|
uint256 nullifierHash = input[1];
|
||||||
|
@ -7,11 +7,11 @@ const MiMC = artifacts.require('MiMC')
|
|||||||
|
|
||||||
module.exports = function(deployer, network, accounts) {
|
module.exports = function(deployer, network, accounts) {
|
||||||
return deployer.then(async () => {
|
return deployer.then(async () => {
|
||||||
const { MERKLE_TREE_HEIGHT, AMOUNT, EMPTY_ELEMENT } = process.env
|
const { MERKLE_TREE_HEIGHT, ETH_AMOUNT, EMPTY_ELEMENT } = process.env
|
||||||
const verifier = await Verifier.deployed()
|
const verifier = await Verifier.deployed()
|
||||||
const miMC = await MiMC.deployed()
|
const miMC = await MiMC.deployed()
|
||||||
await ETHMixer.link(MiMC, miMC.address)
|
await ETHMixer.link(MiMC, miMC.address)
|
||||||
const mixer = await deployer.deploy(ETHMixer, verifier.address, AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT, accounts[0])
|
const mixer = await deployer.deploy(ETHMixer, verifier.address, ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT, accounts[0])
|
||||||
console.log('ETHMixer\'s address ', mixer.address)
|
console.log('ETHMixer\'s address ', mixer.address)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ const ERC20Mock = artifacts.require('ERC20Mock')
|
|||||||
|
|
||||||
module.exports = function(deployer, network, accounts) {
|
module.exports = function(deployer, network, accounts) {
|
||||||
return deployer.then(async () => {
|
return deployer.then(async () => {
|
||||||
const { MERKLE_TREE_HEIGHT, AMOUNT, EMPTY_ELEMENT, ERC20_TOKEN } = process.env
|
const { MERKLE_TREE_HEIGHT, ETH_AMOUNT, EMPTY_ELEMENT, ERC20_TOKEN, TOKEN_AMOUNT } = process.env
|
||||||
const verifier = await Verifier.deployed()
|
const verifier = await Verifier.deployed()
|
||||||
const miMC = await MiMC.deployed()
|
const miMC = await MiMC.deployed()
|
||||||
await ERC20Mixer.link(MiMC, miMC.address)
|
await ERC20Mixer.link(MiMC, miMC.address)
|
||||||
@ -20,11 +20,12 @@ module.exports = function(deployer, network, accounts) {
|
|||||||
const mixer = await deployer.deploy(
|
const mixer = await deployer.deploy(
|
||||||
ERC20Mixer,
|
ERC20Mixer,
|
||||||
verifier.address,
|
verifier.address,
|
||||||
AMOUNT,
|
ETH_AMOUNT,
|
||||||
MERKLE_TREE_HEIGHT,
|
MERKLE_TREE_HEIGHT,
|
||||||
EMPTY_ELEMENT,
|
EMPTY_ELEMENT,
|
||||||
accounts[0],
|
accounts[0],
|
||||||
token
|
token,
|
||||||
|
TOKEN_AMOUNT
|
||||||
)
|
)
|
||||||
console.log('ERC20Mixer\'s address ', mixer.address)
|
console.log('ERC20Mixer\'s address ', mixer.address)
|
||||||
})
|
})
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"migrate:dev": "npx truffle migrate --network development --reset",
|
"migrate:dev": "npx truffle migrate --network development --reset",
|
||||||
"browserify": "npx browserify cli.js -o index.js --exclude worker_threads",
|
"browserify": "npx browserify cli.js -o index.js --exclude worker_threads",
|
||||||
"eslint": "npx eslint --ignore-path .gitignore .",
|
"eslint": "npx eslint --ignore-path .gitignore .",
|
||||||
"flat": "truffle-flattener contracts/Mixer.sol > Mixer_flat.sol"
|
"flat": "truffle-flattener contracts/ETHMixer.sol > ETHMixer_flat.sol contracts/ERC20Mixer.sol > ERC20Mixer_flat.sol"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
@ -5,17 +5,16 @@ require('chai')
|
|||||||
.should()
|
.should()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
const { toBN, toHex, randomHex } = require('web3-utils')
|
const { toBN, toHex } = require('web3-utils')
|
||||||
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
|
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
|
||||||
|
|
||||||
const Mixer = artifacts.require('./ERC20Mixer.sol')
|
const Mixer = artifacts.require('./ERC20Mixer.sol')
|
||||||
const Token = artifacts.require('./ERC20Mock.sol')
|
const Token = artifacts.require('./ERC20Mock.sol')
|
||||||
const { AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
const { ETH_AMOUNT, TOKEN_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
||||||
|
|
||||||
const websnarkUtils = require('websnark/src/utils')
|
const websnarkUtils = require('websnark/src/utils')
|
||||||
const buildGroth16 = require('websnark/src/groth16')
|
const buildGroth16 = require('websnark/src/groth16')
|
||||||
const stringifyBigInts = require('websnark/tools/stringifybigint').stringifyBigInts
|
const stringifyBigInts = require('websnark/tools/stringifybigint').stringifyBigInts
|
||||||
const unstringifyBigInts2 = require('snarkjs/src/stringifybigint').unstringifyBigInts
|
|
||||||
const snarkjs = require('snarkjs')
|
const snarkjs = require('snarkjs')
|
||||||
const bigInt = snarkjs.bigInt
|
const bigInt = snarkjs.bigInt
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
@ -35,15 +34,6 @@ function generateDeposit() {
|
|||||||
return deposit
|
return deposit
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
function BNArrayToStringArray(array) {
|
|
||||||
const arrayToPrint = []
|
|
||||||
array.forEach(item => {
|
|
||||||
arrayToPrint.push(item.toString())
|
|
||||||
})
|
|
||||||
return arrayToPrint
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandomReceiver() {
|
function getRandomReceiver() {
|
||||||
let receiver = rbigint(20)
|
let receiver = rbigint(20)
|
||||||
while (toHex(receiver.toString()).length !== 42) {
|
while (toHex(receiver.toString()).length !== 42) {
|
||||||
@ -52,24 +42,19 @@ function getRandomReceiver() {
|
|||||||
return receiver
|
return receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
function snarkVerify(proof) {
|
contract('ERC20Mixer', accounts => {
|
||||||
proof = unstringifyBigInts2(websnarkUtils.fromSolidityInput(proof))
|
|
||||||
const verification_key = unstringifyBigInts2(require('../build/circuits/withdraw_verification_key.json'))
|
|
||||||
return snarkjs['groth'].isValid(verification_key, proof, proof.publicSignals)
|
|
||||||
}
|
|
||||||
|
|
||||||
contract('Mixer', accounts => {
|
|
||||||
let mixer
|
let mixer
|
||||||
let token
|
let token
|
||||||
const sender = accounts[0]
|
const sender = accounts[0]
|
||||||
const operator = accounts[0]
|
const operator = accounts[0]
|
||||||
const levels = MERKLE_TREE_HEIGHT || 16
|
const levels = MERKLE_TREE_HEIGHT || 16
|
||||||
const zeroValue = EMPTY_ELEMENT || 1337
|
const zeroValue = EMPTY_ELEMENT || 1337
|
||||||
const value = AMOUNT || '1000000000000000000' // 1 ether
|
const tokenDenomination = TOKEN_AMOUNT || '1000000000000000000' // 1 ether
|
||||||
|
const value = ETH_AMOUNT || '1000000000000000000' // 1 ether
|
||||||
let snapshotId
|
let snapshotId
|
||||||
let prefix = 'test'
|
let prefix = 'test'
|
||||||
let tree
|
let tree
|
||||||
const fee = bigInt(AMOUNT).shr(1) || bigInt(1e17)
|
const fee = bigInt(ETH_AMOUNT).shr(1) || bigInt(1e17)
|
||||||
const receiver = getRandomReceiver()
|
const receiver = getRandomReceiver()
|
||||||
const relayer = accounts[1]
|
const relayer = accounts[1]
|
||||||
let groth16
|
let groth16
|
||||||
@ -85,7 +70,7 @@ contract('Mixer', accounts => {
|
|||||||
)
|
)
|
||||||
mixer = await Mixer.deployed()
|
mixer = await Mixer.deployed()
|
||||||
token = await Token.deployed()
|
token = await Token.deployed()
|
||||||
await token.mint(sender, value)
|
await token.mint(sender, tokenDenomination)
|
||||||
snapshotId = await takeSnapshot()
|
snapshotId = await takeSnapshot()
|
||||||
groth16 = await buildGroth16()
|
groth16 = await buildGroth16()
|
||||||
circuit = require('../build/circuits/withdraw.json')
|
circuit = require('../build/circuits/withdraw.json')
|
||||||
@ -102,9 +87,9 @@ contract('Mixer', accounts => {
|
|||||||
describe('#deposit', () => {
|
describe('#deposit', () => {
|
||||||
it('should work', async () => {
|
it('should work', async () => {
|
||||||
const commitment = 43
|
const commitment = 43
|
||||||
await token.approve(mixer.address, value)
|
await token.approve(mixer.address, tokenDenomination)
|
||||||
|
|
||||||
let { logs } = await mixer.deposit(commitment, { from: sender })
|
let { logs } = await mixer.deposit(commitment, { value, from: sender })
|
||||||
|
|
||||||
logs[0].event.should.be.equal('Deposit')
|
logs[0].event.should.be.equal('Deposit')
|
||||||
logs[0].args.commitment.should.be.eq.BN(toBN(commitment))
|
logs[0].args.commitment.should.be.eq.BN(toBN(commitment))
|
||||||
@ -117,17 +102,17 @@ contract('Mixer', accounts => {
|
|||||||
const deposit = generateDeposit()
|
const deposit = generateDeposit()
|
||||||
const user = accounts[4]
|
const user = accounts[4]
|
||||||
await tree.insert(deposit.commitment)
|
await tree.insert(deposit.commitment)
|
||||||
await token.mint(user, value)
|
await token.mint(user, tokenDenomination)
|
||||||
|
|
||||||
const balanceUserBefore = await token.balanceOf(user)
|
const balanceUserBefore = await token.balanceOf(user)
|
||||||
await token.approve(mixer.address, value, { from: user })
|
await token.approve(mixer.address, tokenDenomination, { from: user })
|
||||||
// Uncomment to measure gas usage
|
// Uncomment to measure gas usage
|
||||||
// let gas = await mixer.deposit.estimateGas(toBN(deposit.commitment.toString()), { value, from: user, gasPrice: '0' })
|
// let gas = await mixer.deposit.estimateGas(toBN(deposit.commitment.toString()), { value, from: user, gasPrice: '0' })
|
||||||
// console.log('deposit gas:', gas)
|
// console.log('deposit gas:', gas)
|
||||||
await mixer.deposit(toBN(deposit.commitment.toString()), { from: user, gasPrice: '0' })
|
await mixer.deposit(toBN(deposit.commitment.toString()), { value, from: user, gasPrice: '0' })
|
||||||
|
|
||||||
const balanceUserAfter = await token.balanceOf(user)
|
const balanceUserAfter = await token.balanceOf(user)
|
||||||
balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(value)))
|
balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(tokenDenomination)))
|
||||||
|
|
||||||
const { root, path_elements, path_index } = await tree.path(0)
|
const { root, path_elements, path_index } = await tree.path(0)
|
||||||
|
|
||||||
@ -152,8 +137,9 @@ contract('Mixer', accounts => {
|
|||||||
|
|
||||||
const balanceMixerBefore = await token.balanceOf(mixer.address)
|
const balanceMixerBefore = await token.balanceOf(mixer.address)
|
||||||
const balanceRelayerBefore = await token.balanceOf(relayer)
|
const balanceRelayerBefore = await token.balanceOf(relayer)
|
||||||
const balanceOperatorBefore = await token.balanceOf(operator)
|
const ethBalanceOperatorBefore = await web3.eth.getBalance(operator)
|
||||||
const balanceRecieverBefore = await token.balanceOf(toHex(receiver.toString()))
|
const balanceRecieverBefore = await token.balanceOf(toHex(receiver.toString()))
|
||||||
|
const ethBalanceRecieverBefore = await web3.eth.getBalance(toHex(receiver.toString()))
|
||||||
let isSpent = await mixer.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
|
let isSpent = await mixer.isSpent(input.nullifierHash.toString(16).padStart(66, '0x00000'))
|
||||||
isSpent.should.be.equal(false)
|
isSpent.should.be.equal(false)
|
||||||
|
|
||||||
@ -164,13 +150,15 @@ contract('Mixer', accounts => {
|
|||||||
|
|
||||||
const balanceMixerAfter = await token.balanceOf(mixer.address)
|
const balanceMixerAfter = await token.balanceOf(mixer.address)
|
||||||
const balanceRelayerAfter = await token.balanceOf(relayer)
|
const balanceRelayerAfter = await token.balanceOf(relayer)
|
||||||
const balanceOperatorAfter = await token.balanceOf(operator)
|
const ethBalanceOperatorAfter = await web3.eth.getBalance(operator)
|
||||||
const balanceRecieverAfter = await token.balanceOf(toHex(receiver.toString()))
|
const balanceRecieverAfter = await token.balanceOf(toHex(receiver.toString()))
|
||||||
|
const ethBalanceRecieverAfter = await web3.eth.getBalance(toHex(receiver.toString()))
|
||||||
const feeBN = toBN(fee.toString())
|
const feeBN = toBN(fee.toString())
|
||||||
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(value)))
|
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(tokenDenomination)))
|
||||||
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore))
|
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore))
|
||||||
balanceOperatorAfter.should.be.eq.BN(toBN(balanceOperatorBefore).add(feeBN))
|
ethBalanceOperatorAfter.should.be.eq.BN(toBN(ethBalanceOperatorBefore).add(feeBN))
|
||||||
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(value)).sub(feeBN))
|
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(tokenDenomination)))
|
||||||
|
ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(value)).sub(feeBN))
|
||||||
|
|
||||||
|
|
||||||
logs[0].event.should.be.equal('Withdraw')
|
logs[0].event.should.be.equal('Withdraw')
|
||||||
|
@ -9,7 +9,7 @@ const { toBN, toHex, randomHex } = require('web3-utils')
|
|||||||
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
|
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
|
||||||
|
|
||||||
const Mixer = artifacts.require('./ETHMixer.sol')
|
const Mixer = artifacts.require('./ETHMixer.sol')
|
||||||
const { AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
const { ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
||||||
|
|
||||||
const websnarkUtils = require('websnark/src/utils')
|
const websnarkUtils = require('websnark/src/utils')
|
||||||
const buildGroth16 = require('websnark/src/groth16')
|
const buildGroth16 = require('websnark/src/groth16')
|
||||||
@ -57,17 +57,17 @@ function snarkVerify(proof) {
|
|||||||
return snarkjs['groth'].isValid(verification_key, proof, proof.publicSignals)
|
return snarkjs['groth'].isValid(verification_key, proof, proof.publicSignals)
|
||||||
}
|
}
|
||||||
|
|
||||||
contract('Mixer', accounts => {
|
contract('ETHMixer', accounts => {
|
||||||
let mixer
|
let mixer
|
||||||
const sender = accounts[0]
|
const sender = accounts[0]
|
||||||
const operator = accounts[0]
|
const operator = accounts[0]
|
||||||
const levels = MERKLE_TREE_HEIGHT || 16
|
const levels = MERKLE_TREE_HEIGHT || 16
|
||||||
const zeroValue = EMPTY_ELEMENT || 1337
|
const zeroValue = EMPTY_ELEMENT || 1337
|
||||||
const value = AMOUNT || '1000000000000000000' // 1 ether
|
const value = ETH_AMOUNT || '1000000000000000000' // 1 ether
|
||||||
let snapshotId
|
let snapshotId
|
||||||
let prefix = 'test'
|
let prefix = 'test'
|
||||||
let tree
|
let tree
|
||||||
const fee = bigInt(AMOUNT).shr(1) || bigInt(1e17)
|
const fee = bigInt(ETH_AMOUNT).shr(1) || bigInt(1e17)
|
||||||
const receiver = getRandomReceiver()
|
const receiver = getRandomReceiver()
|
||||||
const relayer = accounts[1]
|
const relayer = accounts[1]
|
||||||
let groth16
|
let groth16
|
||||||
@ -90,8 +90,8 @@ contract('Mixer', accounts => {
|
|||||||
|
|
||||||
describe('#constructor', () => {
|
describe('#constructor', () => {
|
||||||
it('should initialize', async () => {
|
it('should initialize', async () => {
|
||||||
const transferValue = await mixer.transferValue()
|
const etherDenomination = await mixer.etherDenomination()
|
||||||
transferValue.should.be.eq.BN(toBN(value))
|
etherDenomination.should.be.eq.BN(toBN(value))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const MiMC = artifacts.require('./MiMC.sol')
|
|||||||
const MerkleTree = require('../lib/MerkleTree')
|
const MerkleTree = require('../lib/MerkleTree')
|
||||||
const MimcHasher = require('../lib/MiMC')
|
const MimcHasher = require('../lib/MiMC')
|
||||||
|
|
||||||
const { AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
const { ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function BNArrayToStringArray(array) {
|
function BNArrayToStringArray(array) {
|
||||||
@ -30,7 +30,7 @@ contract('MerkleTreeWithHistory', accounts => {
|
|||||||
let zeroValue = EMPTY_ELEMENT || 1337
|
let zeroValue = EMPTY_ELEMENT || 1337
|
||||||
const sender = accounts[0]
|
const sender = accounts[0]
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const value = AMOUNT || '1000000000000000000'
|
const value = ETH_AMOUNT || '1000000000000000000'
|
||||||
let snapshotId
|
let snapshotId
|
||||||
let prefix = 'test'
|
let prefix = 'test'
|
||||||
let tree
|
let tree
|
||||||
|
@ -77,7 +77,7 @@ module.exports = {
|
|||||||
// Configure your compilers
|
// Configure your compilers
|
||||||
compilers: {
|
compilers: {
|
||||||
solc: {
|
solc: {
|
||||||
version: '0.5.10', // Fetch exact version from solc-bin (default: truffle's version)
|
version: '0.5.11', // Fetch exact version from solc-bin (default: truffle's version)
|
||||||
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
|
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
|
||||||
settings: { // See the solidity docs for advice about optimization and evmVersion
|
settings: { // See the solidity docs for advice about optimization and evmVersion
|
||||||
optimizer: {
|
optimizer: {
|
||||||
|
Loading…
Reference in New Issue
Block a user