Merge pull request #18 from peppersec/audit-2

Code style fixes for audit (batch 2)
This commit is contained in:
Roman Semenov 2019-11-06 01:09:46 +03:00 committed by GitHub
commit fce4b1854c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 130 additions and 182 deletions

View File

@ -2,7 +2,6 @@ MERKLE_TREE_HEIGHT=16
# in wei # in wei
ETH_AMOUNT=100000000000000000 ETH_AMOUNT=100000000000000000
TOKEN_AMOUNT=100000000000000000 TOKEN_AMOUNT=100000000000000000
EMPTY_ELEMENT=1
PRIVATE_KEY= PRIVATE_KEY=
ERC20_TOKEN= ERC20_TOKEN=

8
cli.js
View File

@ -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, erc20mixer, circuit, proving_key, groth16, erc20 let web3, mixer, erc20mixer, circuit, proving_key, groth16, erc20
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, EMPTY_ELEMENT, ERC20_TOKEN let MERKLE_TREE_HEIGHT, ETH_AMOUNT, ERC20_TOKEN
const inBrowser = (typeof window !== 'undefined') const inBrowser = (typeof window !== 'undefined')
/** Generate random number of specified byte length */ /** Generate random number of specified byte length */
@ -83,7 +83,7 @@ async function withdrawErc20(note, receiver, relayer) {
} }
return e.returnValues.commitment return e.returnValues.commitment
}) })
const tree = new merkleTree(MERKLE_TREE_HEIGHT, EMPTY_ELEMENT, leaves) const tree = new merkleTree(MERKLE_TREE_HEIGHT, leaves)
const validRoot = await erc20mixer.methods.isKnownRoot(await tree.root()).call() const validRoot = await erc20mixer.methods.isKnownRoot(await tree.root()).call()
const nullifierHash = pedersenHash(deposit.nullifier.leInt2Buff(31)) const nullifierHash = pedersenHash(deposit.nullifier.leInt2Buff(31))
const nullifierHashToCheck = nullifierHash.toString(16).padStart('66', '0x000000') const nullifierHashToCheck = nullifierHash.toString(16).padStart('66', '0x000000')
@ -152,7 +152,7 @@ async function withdraw(note, receiver) {
const leaves = events const leaves = events
.sort((a, b) => a.returnValues.leafIndex.sub(b.returnValues.leafIndex)) // Sort events in chronological order .sort((a, b) => a.returnValues.leafIndex.sub(b.returnValues.leafIndex)) // Sort events in chronological order
.map(e => e.returnValues.commitment) .map(e => e.returnValues.commitment)
const tree = new merkleTree(MERKLE_TREE_HEIGHT, EMPTY_ELEMENT, leaves) const tree = new merkleTree(MERKLE_TREE_HEIGHT, leaves)
// Find current commitment in the tree // Find current commitment in the tree
let depositEvent = events.find(e => e.returnValues.commitment.eq(paddedCommitment)) let depositEvent = events.find(e => e.returnValues.commitment.eq(paddedCommitment))
@ -210,7 +210,6 @@ async function init() {
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
ETH_AMOUNT = 1e18 ETH_AMOUNT = 1e18
EMPTY_ELEMENT = 1
} else { } else {
// Initialize from local node // Initialize from local node
web3 = new Web3('http://localhost:8545', null, { transactionConfirmationBlocks: 1 }) web3 = new Web3('http://localhost:8545', null, { transactionConfirmationBlocks: 1 })
@ -220,7 +219,6 @@ async function init() {
require('dotenv').config() require('dotenv').config()
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT
ETH_AMOUNT = process.env.ETH_AMOUNT ETH_AMOUNT = process.env.ETH_AMOUNT
EMPTY_ELEMENT = process.env.EMPTY_ELEMENT
ERC20_TOKEN = process.env.ERC20_TOKEN ERC20_TOKEN = process.env.ERC20_TOKEN
erc20ContractJson = require('./build/contracts/ERC20Mock.json') erc20ContractJson = require('./build/contracts/ERC20Mock.json')
erc20mixerJson = require('./build/contracts/ERC20Mixer.json') erc20mixerJson = require('./build/contracts/ERC20Mixer.json')

View File

@ -20,68 +20,49 @@ contract ERC20Mixer is Mixer {
IVerifier _verifier, IVerifier _verifier,
uint256 _denomination, uint256 _denomination,
uint8 _merkleTreeHeight, uint8 _merkleTreeHeight,
uint256 _emptyElement,
address _operator, address _operator,
address _token address _token
) Mixer(_verifier, _denomination, _merkleTreeHeight, _emptyElement, _operator) public { ) Mixer(_verifier, _denomination, _merkleTreeHeight, _operator) public {
token = _token; token = _token;
} }
function _processDeposit() internal { function _processDeposit() internal {
require(msg.value == 0, "ETH value is supposed to be 0 for ETH mixer"); require(msg.value == 0, "ETH value is supposed to be 0 for ETH mixer");
safeErc20TransferFrom(msg.sender, address(this), denomination); _safeErc20TransferFrom(msg.sender, address(this), denomination);
} }
function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal { function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal {
require(msg.value == _refund, "Incorrect refund amount received by the contract"); require(msg.value == _refund, "Incorrect refund amount received by the contract");
safeErc20Transfer(_receiver, denomination - _fee); _safeErc20Transfer(_receiver, denomination - _fee);
if (_fee > 0) { if (_fee > 0) {
safeErc20Transfer(_relayer, _fee); _safeErc20Transfer(_relayer, _fee);
} }
if (_refund > 0) { if (_refund > 0) {
_receiver.transfer(_refund); _receiver.transfer(_refund);
} }
} }
function safeErc20TransferFrom(address from, address to, uint256 amount) internal { function _safeErc20TransferFrom(address _from, address _to, uint256 _amount) internal {
bool success; (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd /* transferFrom */, _from, _to, _amount));
bytes memory data;
bytes4 transferFromSelector = 0x23b872dd;
(success, data) = token.call(
abi.encodeWithSelector(
transferFromSelector,
from, to, amount
)
);
require(success, "not enough allowed tokens"); require(success, "not enough allowed tokens");
// if contract returns some data let's make sure that is `true` according to standard // if contract returns some data lets make sure that is `true` according to standard
if (data.length > 0) { if (data.length > 0) {
assembly { require(data.length == 32, "data length should be either 0 or 32 bytes");
success := mload(add(data, 0x20)) success = abi.decode(data, (bool));
}
require(success, "not enough allowed tokens"); require(success, "not enough allowed tokens");
} }
} }
function safeErc20Transfer(address to, uint256 amount) internal { function _safeErc20Transfer(address _to, uint256 _amount) internal {
bool success; (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb /* transfer */, _to, _amount));
bytes memory data;
bytes4 transferSelector = 0xa9059cbb;
(success, data) = token.call(
abi.encodeWithSelector(
transferSelector,
to, amount
)
);
require(success, "not enough tokens"); require(success, "not enough tokens");
// if contract returns some data let's make sure that is `true` according to standard // if contract returns some data lets make sure that is `true` according to standard
if (data.length > 0) { if (data.length > 0) {
assembly { require(data.length == 32, "data length should be either 0 or 32 bytes");
success := mload(add(data, 0x20)) success = abi.decode(data, (bool));
}
require(success, "not enough tokens"); require(success, "not enough tokens");
} }
} }

View File

@ -18,9 +18,12 @@ contract ETHMixer is Mixer {
IVerifier _verifier, IVerifier _verifier,
uint256 _denomination, uint256 _denomination,
uint8 _merkleTreeHeight, uint8 _merkleTreeHeight,
uint256 _emptyElement,
address _operator address _operator
) Mixer(_verifier, _denomination, _merkleTreeHeight, _emptyElement, _operator) public { ) Mixer(_verifier, _denomination, _merkleTreeHeight, _operator) public {
}
function _processDeposit() internal {
require(msg.value == denomination, "Please send `mixDenomination` ETH along with transaction");
} }
function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal { function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal {
@ -33,8 +36,4 @@ contract ETHMixer is Mixer {
_relayer.transfer(_fee); _relayer.transfer(_fee);
} }
} }
function _processDeposit() internal {
require(msg.value == denomination, "Please send `mixDenomination` ETH along with transaction");
}
} }

View File

@ -16,122 +16,108 @@ library Hasher {
} }
contract MerkleTreeWithHistory { contract MerkleTreeWithHistory {
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 public constant ZERO_VALUE = 5702960885942360421128284892092891246826997279710054143430547229469817701242; // = MiMC("tornado")
uint256 public levels; uint256 public levels;
uint256 constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // the following variables are made public for easier testing and debugging and
uint256 constant ROOT_HISTORY_SIZE = 100; // are not supposed to be accessed in regular code
uint256[ROOT_HISTORY_SIZE] public _roots; uint256 public constant ROOT_HISTORY_SIZE = 100;
uint256 public current_root_index = 0; uint256[ROOT_HISTORY_SIZE] public roots;
uint256 public currentRootIndex = 0;
uint32 public nextIndex = 0;
uint256[] public filledSubtrees;
uint256[] public zeros;
uint256[] private _filled_subtrees; constructor(uint256 _treeLevels) public {
uint256[] private _zeros; require(_treeLevels > 0, "_treeLevels should be greater than zero");
levels = _treeLevels;
uint32 public next_index = 0; uint256 currentZero = ZERO_VALUE;
zeros.push(currentZero);
constructor(uint256 tree_levels, uint256 zero_value) public { filledSubtrees.push(currentZero);
require(tree_levels > 0, "tree_levels should be greater than zero");
levels = tree_levels;
uint256 current_zero = zero_value;
_zeros.push(zero_value);
_filled_subtrees.push(current_zero);
for (uint8 i = 1; i < levels; i++) { for (uint8 i = 1; i < levels; i++) {
current_zero = hashLeftRight(current_zero, current_zero); currentZero = hashLeftRight(currentZero, currentZero);
_zeros.push(current_zero); zeros.push(currentZero);
_filled_subtrees.push(current_zero); filledSubtrees.push(currentZero);
} }
_roots[0] = hashLeftRight(current_zero, current_zero); roots[0] = hashLeftRight(currentZero, currentZero);
} }
function hashLeftRight(uint256 left, uint256 right) public pure returns (uint256 hash) { /**
uint256 R = left; // left is already checked to be less than field_size by snark verifier @dev Hash 2 tree leaves, returns MiMC(_left, _right)
*/
function hashLeftRight(uint256 _left, uint256 _right) public pure returns (uint256) {
require(_left < FIELD_SIZE, "_left should be inside the field");
require(_right < FIELD_SIZE, "_right should be inside the field");
uint256 R = _left;
uint256 C = 0; uint256 C = 0;
(R, C) = Hasher.MiMCSponge(R, C, 0); (R, C) = Hasher.MiMCSponge(R, C, 0);
R = addmod(R, _right, FIELD_SIZE);
R = addmod(R, right, FIELD_SIZE);
(R, C) = Hasher.MiMCSponge(R, C, 0); (R, C) = Hasher.MiMCSponge(R, C, 0);
return R; return R;
} }
function _insert(uint256 leaf) internal returns(uint256 index) { function _insert(uint256 _leaf) internal returns(uint256 index) {
uint32 current_index = next_index; uint32 currentIndex = nextIndex;
require(current_index != 2**levels, "Merkle tree is full. No more leafs can be added"); require(currentIndex != 2**levels, "Merkle tree is full. No more leafs can be added");
next_index += 1; nextIndex += 1;
uint256 current_level_hash = leaf; uint256 currentLevelHash = _leaf;
uint256 left; uint256 left;
uint256 right; uint256 right;
for (uint256 i = 0; i < levels; i++) { for (uint256 i = 0; i < levels; i++) {
if (current_index % 2 == 0) { if (currentIndex % 2 == 0) {
left = current_level_hash; left = currentLevelHash;
right = _zeros[i]; right = zeros[i];
_filled_subtrees[i] = current_level_hash; filledSubtrees[i] = currentLevelHash;
} else { } else {
left = _filled_subtrees[i]; left = filledSubtrees[i];
right = current_level_hash; right = currentLevelHash;
} }
current_level_hash = hashLeftRight(left, right); currentLevelHash = hashLeftRight(left, right);
current_index /= 2; currentIndex /= 2;
} }
current_root_index = (current_root_index + 1) % ROOT_HISTORY_SIZE; currentRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
_roots[current_root_index] = current_level_hash; roots[currentRootIndex] = currentLevelHash;
return next_index - 1; return nextIndex - 1;
} }
function isKnownRoot(uint256 root) public view returns(bool) { /**
if (root == 0) { @dev Whether the root is present in the root history
*/
function isKnownRoot(uint256 _root) public view returns(bool) {
if (_root == 0) {
return false; return false;
} }
// search most recent first // search most recent first
uint256 i; uint256 i;
for(i = current_root_index; i < 2**256 - 1; i--) { for(i = currentRootIndex; i < 2**256 - 1; i--) {
if (root == _roots[i]) { if (_root == roots[i]) {
return true; return true;
} }
} }
// process the rest of roots // process the rest of roots
for(i = ROOT_HISTORY_SIZE - 1; i > current_root_index; i--) { for(i = ROOT_HISTORY_SIZE - 1; i > currentRootIndex; i--) {
if (root == _roots[i]) { if (_root == roots[i]) {
return true; return true;
} }
} }
return false; return false;
// or we can do that in other way
// uint256 i = _current_root;
// do {
// if (root == _roots[i]) {
// return true;
// }
// if (i == 0) {
// i = ROOT_HISTORY_SIZE;
// }
// i--;
// } while (i != _current_root);
} }
/**
@dev Returns the last root
*/
function getLastRoot() public view returns(uint256) { function getLastRoot() public view returns(uint256) {
return _roots[current_root_index]; return roots[currentRootIndex];
}
function roots() public view returns(uint256[ROOT_HISTORY_SIZE] memory) {
return _roots;
}
function filled_subtrees() public view returns(uint256[] memory) {
return _filled_subtrees;
}
function zeros() public view returns(uint256[] memory) {
return _zeros;
} }
} }

View File

@ -14,7 +14,7 @@ pragma solidity ^0.5.8;
import "./MerkleTreeWithHistory.sol"; import "./MerkleTreeWithHistory.sol";
contract IVerifier { contract IVerifier {
function verifyProof(uint256[8] memory proof, uint256[6] memory input) public returns(bool); function verifyProof(uint256[8] memory _proof, uint256[6] memory _input) public returns(bool);
} }
contract Mixer is MerkleTreeWithHistory { contract Mixer is MerkleTreeWithHistory {
@ -25,7 +25,6 @@ contract Mixer is MerkleTreeWithHistory {
IVerifier public verifier; IVerifier public verifier;
// operator can // operator can
// - receive a relayer fee
// - disable new deposits in case of emergency // - disable new deposits in case of emergency
// - update snark verification key until this ability is permanently disabled // - update snark verification key until this ability is permanently disabled
address public operator; address public operator;
@ -37,22 +36,21 @@ contract Mixer is MerkleTreeWithHistory {
} }
event Deposit(uint256 indexed commitment, uint256 leafIndex, uint256 timestamp); event Deposit(uint256 indexed commitment, uint256 leafIndex, uint256 timestamp);
event Withdraw(address to, uint256 nullifierHash, address indexed relayer, uint256 fee); event Withdrawal(address to, uint256 nullifierHash, address indexed relayer, uint256 fee);
/** /**
@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 _denomination transfer amount for each deposit
@param _merkleTreeHeight the height of deposits' Merkle Tree @param _merkleTreeHeight the height of deposits' Merkle Tree
@param _emptyElement default element of the deposits' Merkle Tree @param _operator operator address (see operator comment above)
@param _operator operator address (see operator above)
*/ */
constructor( constructor(
IVerifier _verifier, IVerifier _verifier,
uint256 _denomination, uint256 _denomination,
uint8 _merkleTreeHeight, uint8 _merkleTreeHeight,
uint256 _emptyElement,
address _operator address _operator
) MerkleTreeWithHistory(_merkleTreeHeight, _emptyElement) public { ) MerkleTreeWithHistory(_merkleTreeHeight) public {
require(_denomination > 0, "denomination should be greater than 0"); require(_denomination > 0, "denomination should be greater than 0");
verifier = _verifier; verifier = _verifier;
operator = _operator; operator = _operator;
@ -61,52 +59,52 @@ contract Mixer is MerkleTreeWithHistory {
/** /**
@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 mixer. The caller must send (for ETH) or approve (for ERC20) value equal to or `denomination` of this mixer.
@param commitment the note commitment, which is PedersenHash(nullifier + secret) @param _commitment the note commitment, which is PedersenHash(nullifier + secret)
*/ */
function deposit(uint256 commitment) public payable { function deposit(uint256 _commitment) public payable {
require(!isDepositsDisabled, "deposits are disabled"); require(!isDepositsDisabled, "deposits are disabled");
require(!commitments[commitment], "The commitment has been submitted"); require(!commitments[_commitment], "The commitment has been submitted");
uint256 insertedIndex = _insert(commitment); uint256 insertedIndex = _insert(_commitment);
commitments[commitment] = true; commitments[_commitment] = true;
_processDeposit(); _processDeposit();
emit Deposit(commitment, insertedIndex, block.timestamp); emit Deposit(_commitment, insertedIndex, block.timestamp);
} }
/** @dev this function is defined in a child contract */ /** @dev this function is defined in a child contract */
function _processDeposit() internal; function _processDeposit() internal;
/** /**
@dev Withdraw 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 mixer. `proof` is a zkSNARK proof data, and input is an array of circuit public inputs
`input` array consists of: `input` array consists of:
- merkle root of all deposits in the mixer - merkle root of all deposits in the mixer
- hash of unique deposit nullifier to prevent double spends - hash of unique deposit nullifier to prevent double spends
- the receiver of funds - the receiver of funds
- optional fee that goes to the transaction sender (usually a relay) - optional fee that goes to the transaction sender (usually a relay)
*/ */
function withdraw(uint256[8] memory proof, uint256[6] memory input) public payable { function withdraw(uint256[8] memory _proof, uint256[6] memory _input) public payable {
uint256 root = input[0]; uint256 root = _input[0];
uint256 nullifierHash = input[1]; uint256 nullifierHash = _input[1];
address payable receiver = address(input[2]); address payable receiver = address(_input[2]);
address payable relayer = address(input[3]); address payable relayer = address(_input[3]);
uint256 fee = input[4]; uint256 fee = _input[4];
uint256 refund = input[5]; uint256 refund = _input[5];
require(fee <= denomination, "Fee exceeds transfer value"); require(fee <= denomination, "Fee exceeds transfer value");
require(!nullifierHashes[nullifierHash], "The note has been already spent"); require(!nullifierHashes[nullifierHash], "The note has been already spent");
require(isKnownRoot(root), "Cannot find your merkle root"); // Make sure to use a recent one require(isKnownRoot(root), "Cannot find your merkle root"); // Make sure to use a recent one
require(verifier.verifyProof(proof, input), "Invalid withdraw proof"); require(verifier.verifyProof(_proof, _input), "Invalid withdraw proof");
nullifierHashes[nullifierHash] = true; nullifierHashes[nullifierHash] = true;
_processWithdraw(receiver, relayer, fee, refund); _processWithdraw(receiver, relayer, fee, refund);
emit Withdraw(receiver, nullifierHash, relayer, fee); emit Withdrawal(receiver, nullifierHash, relayer, fee);
} }
/** @dev this function is defined in a child contract */ /** @dev this function is defined in a child contract */
function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal; function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal;
/** @dev whether a note is already spent */ /** @dev whether a note is already spent */
function isSpent(uint256 nullifierHash) public view returns(bool) { function isSpent(uint256 _nullifierHash) public view returns(bool) {
return nullifierHashes[nullifierHash]; return nullifierHashes[_nullifierHash];
} }
/** /**
@ -121,9 +119,9 @@ contract Mixer is MerkleTreeWithHistory {
@dev allow operator to update SNARK verification keys. This is needed to update keys after the final trusted setup ceremony is held. @dev allow operator to update SNARK verification keys. This is needed to update keys after the final trusted setup ceremony is held.
After that operator is supposed to permanently disable this ability. After that operator is supposed to permanently disable this ability.
*/ */
function updateVerifier(address newVerifier) external onlyOperator { function updateVerifier(address _newVerifier) external onlyOperator {
require(!isVerifierUpdateDisabled, "Verifier updates have been disabled."); require(!isVerifierUpdateDisabled, "Verifier updates have been disabled.");
verifier = IVerifier(newVerifier); verifier = IVerifier(_newVerifier);
} }
/** /**

View File

@ -4,9 +4,9 @@ import '../MerkleTreeWithHistory.sol';
contract MerkleTreeWithHistoryMock is MerkleTreeWithHistory { contract MerkleTreeWithHistoryMock is MerkleTreeWithHistory {
constructor (uint8 tree_levels, uint256 zero_value) MerkleTreeWithHistory(tree_levels, zero_value) public {} constructor (uint8 _treeLevels) MerkleTreeWithHistory(_treeLevels) public {}
function insert(uint256 leaf) public { function insert(uint256 _leaf) public {
_insert(leaf); _insert(_leaf);
} }
} }

View File

@ -1,9 +1,10 @@
const jsStorage = require('./Storage') const jsStorage = require('./Storage')
const hasherImpl = require('./MiMC') const hasherImpl = require('./MiMC')
const { bigInt } = require('snarkjs')
class MerkleTree { class MerkleTree {
constructor(n_levels, zero_value, defaultElements, prefix, storage, hasher) { constructor(n_levels, defaultElements, prefix, storage, hasher) {
this.prefix = prefix this.prefix = prefix
this.storage = storage || new jsStorage() this.storage = storage || new jsStorage()
this.hasher = hasher || new hasherImpl() this.hasher = hasher || new hasherImpl()
@ -11,7 +12,7 @@ class MerkleTree {
this.zero_values = [] this.zero_values = []
this.totalElements = 0 this.totalElements = 0
let current_zero_value = zero_value || 0 let current_zero_value = bigInt('5702960885942360421128284892092891246826997279710054143430547229469817701242')
this.zero_values.push(current_zero_value) this.zero_values.push(current_zero_value)
for (let i = 0; i < n_levels; i++) { for (let i = 0; i < n_levels; i++) {
current_zero_value = this.hasher.hash(i, current_zero_value, current_zero_value) current_zero_value = this.hasher.hash(i, current_zero_value, current_zero_value)

View File

@ -7,11 +7,11 @@ const hasherContract = artifacts.require('Hasher')
module.exports = function(deployer, network, accounts) { module.exports = function(deployer, network, accounts) {
return deployer.then(async () => { return deployer.then(async () => {
const { MERKLE_TREE_HEIGHT, ETH_AMOUNT, EMPTY_ELEMENT } = process.env const { MERKLE_TREE_HEIGHT, ETH_AMOUNT } = process.env
const verifier = await Verifier.deployed() const verifier = await Verifier.deployed()
const hasherInstance = await hasherContract.deployed() const hasherInstance = await hasherContract.deployed()
await ETHMixer.link(hasherContract, hasherInstance.address) await ETHMixer.link(hasherContract, hasherInstance.address)
const mixer = await deployer.deploy(ETHMixer, verifier.address, ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT, accounts[0]) const mixer = await deployer.deploy(ETHMixer, verifier.address, ETH_AMOUNT, MERKLE_TREE_HEIGHT, accounts[0])
console.log('ETHMixer\'s address ', mixer.address) console.log('ETHMixer\'s address ', mixer.address)
}) })
} }

View File

@ -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, EMPTY_ELEMENT, ERC20_TOKEN, TOKEN_AMOUNT } = process.env const { MERKLE_TREE_HEIGHT, ERC20_TOKEN, TOKEN_AMOUNT } = process.env
const verifier = await Verifier.deployed() const verifier = await Verifier.deployed()
const hasherInstance = await hasherContract.deployed() const hasherInstance = await hasherContract.deployed()
await ERC20Mixer.link(hasherContract, hasherInstance.address) await ERC20Mixer.link(hasherContract, hasherInstance.address)
@ -22,7 +22,6 @@ module.exports = function(deployer, network, accounts) {
verifier.address, verifier.address,
TOKEN_AMOUNT, TOKEN_AMOUNT,
MERKLE_TREE_HEIGHT, MERKLE_TREE_HEIGHT,
EMPTY_ELEMENT,
accounts[0], accounts[0],
token, token,
) )

View File

@ -11,7 +11,7 @@ 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 USDTToken = artifacts.require('./IUSDT.sol') const USDTToken = artifacts.require('./IUSDT.sol')
const { ETH_AMOUNT, TOKEN_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT, ERC20_TOKEN } = process.env const { ETH_AMOUNT, TOKEN_AMOUNT, MERKLE_TREE_HEIGHT, ERC20_TOKEN } = 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')
@ -50,7 +50,6 @@ contract('ERC20Mixer', accounts => {
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
let tokenDenomination = TOKEN_AMOUNT || '1000000000000000000' // 1 ether let tokenDenomination = TOKEN_AMOUNT || '1000000000000000000' // 1 ether
let snapshotId let snapshotId
let prefix = 'test' let prefix = 'test'
@ -66,7 +65,6 @@ contract('ERC20Mixer', accounts => {
before(async () => { before(async () => {
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
null, null,
prefix, prefix,
) )
@ -180,7 +178,7 @@ contract('ERC20Mixer', accounts => {
ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(refund))) ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(refund)))
ethBalanceRelayerAfter.should.be.eq.BN(toBN(ethBalanceRelayerBefore).sub(toBN(refund))) ethBalanceRelayerAfter.should.be.eq.BN(toBN(ethBalanceRelayerBefore).sub(toBN(refund)))
logs[0].event.should.be.equal('Withdraw') logs[0].event.should.be.equal('Withdrawal')
logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString())) logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString()))
logs[0].args.relayer.should.be.eq.BN(relayer) logs[0].args.relayer.should.be.eq.BN(relayer)
logs[0].args.fee.should.be.eq.BN(feeBN) logs[0].args.fee.should.be.eq.BN(feeBN)
@ -304,7 +302,7 @@ contract('ERC20Mixer', accounts => {
ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(refund)).sub(feeBN)) ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(refund)).sub(feeBN))
logs[0].event.should.be.equal('Withdraw') logs[0].event.should.be.equal('Withdrawal')
logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString())) logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString()))
logs[0].args.relayer.should.be.eq.BN(operator) logs[0].args.relayer.should.be.eq.BN(operator)
logs[0].args.fee.should.be.eq.BN(feeBN) logs[0].args.fee.should.be.eq.BN(feeBN)
@ -386,7 +384,7 @@ contract('ERC20Mixer', accounts => {
ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(refund)).sub(feeBN)) ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore).add(toBN(refund)).sub(feeBN))
logs[0].event.should.be.equal('Withdraw') logs[0].event.should.be.equal('Withdrawal')
logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString())) logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString()))
logs[0].args.relayer.should.be.eq.BN(operator) logs[0].args.relayer.should.be.eq.BN(operator)
logs[0].args.fee.should.be.eq.BN(feeBN) logs[0].args.fee.should.be.eq.BN(feeBN)
@ -401,7 +399,6 @@ contract('ERC20Mixer', accounts => {
snapshotId = await takeSnapshot() snapshotId = await takeSnapshot()
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
null, null,
prefix, prefix,
) )

View File

@ -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 { ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env const { ETH_AMOUNT, MERKLE_TREE_HEIGHT } = 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')
@ -62,7 +62,6 @@ contract('ETHMixer', accounts => {
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 value = ETH_AMOUNT || '1000000000000000000' // 1 ether const value = ETH_AMOUNT || '1000000000000000000' // 1 ether
let snapshotId let snapshotId
let prefix = 'test' let prefix = 'test'
@ -78,7 +77,6 @@ contract('ETHMixer', accounts => {
before(async () => { before(async () => {
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
null, null,
prefix, prefix,
) )
@ -242,7 +240,7 @@ contract('ETHMixer', accounts => {
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(value)).sub(feeBN)) balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(value)).sub(feeBN))
logs[0].event.should.be.equal('Withdraw') logs[0].event.should.be.equal('Withdrawal')
logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString())) logs[0].args.nullifierHash.should.be.eq.BN(toBN(input.nullifierHash.toString()))
logs[0].args.relayer.should.be.eq.BN(operator) logs[0].args.relayer.should.be.eq.BN(operator)
logs[0].args.fee.should.be.eq.BN(feeBN) logs[0].args.fee.should.be.eq.BN(feeBN)
@ -521,7 +519,6 @@ contract('ETHMixer', accounts => {
snapshotId = await takeSnapshot() snapshotId = await takeSnapshot()
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
null, null,
prefix, prefix,
) )

View File

@ -12,7 +12,7 @@ const hasherContract = artifacts.require('./Hasher.sol')
const MerkleTree = require('../lib/MerkleTree') const MerkleTree = require('../lib/MerkleTree')
const hasherImpl = require('../lib/MiMC') const hasherImpl = require('../lib/MiMC')
const { ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env const { ETH_AMOUNT, MERKLE_TREE_HEIGHT } = process.env
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
function BNArrayToStringArray(array) { function BNArrayToStringArray(array) {
@ -27,7 +27,6 @@ contract('MerkleTreeWithHistory', accounts => {
let merkleTreeWithHistory let merkleTreeWithHistory
let hasherInstance let hasherInstance
let levels = MERKLE_TREE_HEIGHT || 16 let levels = MERKLE_TREE_HEIGHT || 16
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 = ETH_AMOUNT || '1000000000000000000' const value = ETH_AMOUNT || '1000000000000000000'
@ -39,22 +38,22 @@ contract('MerkleTreeWithHistory', accounts => {
before(async () => { before(async () => {
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
null, null,
prefix, prefix,
) )
hasherInstance = await hasherContract.deployed() hasherInstance = await hasherContract.deployed()
await MerkleTreeWithHistory.link(hasherContract, hasherInstance.address) await MerkleTreeWithHistory.link(hasherContract, hasherInstance.address)
merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels, zeroValue) merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels)
snapshotId = await takeSnapshot() snapshotId = await takeSnapshot()
}) })
describe('#constructor', () => { describe('#constructor', () => {
it('should initialize', async () => { it('should initialize', async () => {
const filled_subtrees = await merkleTreeWithHistory.filled_subtrees() const zeroValue = await merkleTreeWithHistory.ZERO_VALUE()
filled_subtrees[0].should.be.eq.BN(zeroValue) const firstSubtree = await merkleTreeWithHistory.filledSubtrees(0)
const zeros = await merkleTreeWithHistory.zeros() firstSubtree.should.be.eq.BN(zeroValue)
zeros[0].should.be.eq.BN(zeroValue) const firstZero = await merkleTreeWithHistory.zeros(0)
firstZero.should.be.eq.BN(zeroValue)
}) })
}) })
@ -70,7 +69,6 @@ contract('MerkleTreeWithHistory', accounts => {
hasher = new hasherImpl() hasher = new hasherImpl()
tree = new MerkleTree( tree = new MerkleTree(
2, 2,
zeroValue,
null, null,
prefix, prefix,
) )
@ -91,7 +89,6 @@ contract('MerkleTreeWithHistory', accounts => {
const batchTree = new MerkleTree( const batchTree = new MerkleTree(
levels, levels,
zeroValue,
elements, elements,
prefix, prefix,
) )
@ -131,7 +128,6 @@ contract('MerkleTreeWithHistory', accounts => {
const batchTree = new MerkleTree( const batchTree = new MerkleTree(
levels, levels,
zeroValue,
elements, elements,
prefix, prefix,
) )
@ -150,7 +146,6 @@ contract('MerkleTreeWithHistory', accounts => {
console.time('MerkleTree') console.time('MerkleTree')
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
elements, elements,
prefix, prefix,
) )
@ -177,8 +172,7 @@ contract('MerkleTreeWithHistory', accounts => {
it('should reject if tree is full', async () => { it('should reject if tree is full', async () => {
levels = 6 levels = 6
zeroValue = 1337 merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels)
merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels, zeroValue)
for (let i = 0; i < 2**levels; i++) { for (let i = 0; i < 2**levels; i++) {
await merkleTreeWithHistory.insert(i+42).should.be.fulfilled await merkleTreeWithHistory.insert(i+42).should.be.fulfilled
@ -193,8 +187,8 @@ contract('MerkleTreeWithHistory', accounts => {
it.skip('hasher gas', async () => { it.skip('hasher gas', async () => {
levels = 6 levels = 6
zeroValue = 1337 merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels)
merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels, zeroValue) const zeroValue = await merkleTreeWithHistory.zeroValue()
const gas = await merkleTreeWithHistory.hashLeftRight.estimateGas(zeroValue, zeroValue) const gas = await merkleTreeWithHistory.hashLeftRight.estimateGas(zeroValue, zeroValue)
console.log('gas', gas - 21000) console.log('gas', gas - 21000)
@ -208,7 +202,6 @@ contract('MerkleTreeWithHistory', accounts => {
hasher = new hasherImpl() hasher = new hasherImpl()
tree = new MerkleTree( tree = new MerkleTree(
levels, levels,
zeroValue,
null, null,
prefix, prefix,
null, null,