mirror of
https://github.com/tornadocash/tornado-core.git
synced 2024-10-01 01:06:17 -04:00
Merge pull request #18 from peppersec/audit-2
Code style fixes for audit (batch 2)
This commit is contained in:
commit
fce4b1854c
@ -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
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, 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')
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user