This commit is contained in:
poma 2019-11-04 22:45:56 +03:00
parent ae889b5ad2
commit 27e3121bb0
4 changed files with 22 additions and 13 deletions

View File

@ -47,7 +47,7 @@ contract ERC20Mixer is Mixer {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd /* transferFrom */, _from, _to, _amount)); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd /* transferFrom */, _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) {
require(data.length == 32, "data length should be either 0 or 32 bytes"); require(data.length == 32, "data length should be either 0 or 32 bytes");
success = abi.decode(data, (bool)); success = abi.decode(data, (bool));
@ -59,7 +59,7 @@ contract ERC20Mixer is Mixer {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb /* transfer */, _to, _amount)); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb /* transfer */, _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) {
require(data.length == 32, "data length should be either 0 or 32 bytes"); require(data.length == 32, "data length should be either 0 or 32 bytes");
success = abi.decode(data, (bool)); success = abi.decode(data, (bool));

View File

@ -22,6 +22,10 @@ contract ETHMixer is Mixer {
) Mixer(_verifier, _denomination, _merkleTreeHeight, _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 {
// sanity checks // sanity checks
require(msg.value == 0, "Message value is supposed to be zero for ETH mixer"); require(msg.value == 0, "Message value is supposed to be zero for ETH mixer");
@ -32,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

@ -19,11 +19,13 @@ contract MerkleTreeWithHistory {
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 public constant ZERO_VALUE = 5702960885942360421128284892092891246826997279710054143430547229469817701242; // = MiMC("tornado") uint256 public constant ZERO_VALUE = 5702960885942360421128284892092891246826997279710054143430547229469817701242; // = MiMC("tornado")
uint256 public levels;
// the following variables are made public for easier testing and debugging and
// are not supposed to be accessed in regular code
uint256 public constant ROOT_HISTORY_SIZE = 100; uint256 public constant ROOT_HISTORY_SIZE = 100;
uint256[ROOT_HISTORY_SIZE] public roots; uint256[ROOT_HISTORY_SIZE] public roots;
uint256 public currentRootIndex = 0; uint256 public currentRootIndex = 0;
uint256 public levels;
uint32 public nextIndex = 0; uint32 public nextIndex = 0;
uint256[] public filledSubtrees; uint256[] public filledSubtrees;
uint256[] public zeros; uint256[] public zeros;
@ -45,9 +47,10 @@ contract MerkleTreeWithHistory {
roots[0] = hashLeftRight(currentZero, currentZero); roots[0] = hashLeftRight(currentZero, currentZero);
} }
/**
@dev Hash 2 tree leaves, returns MiMC(_left, _right)
*/
function hashLeftRight(uint256 _left, uint256 _right) public pure returns (uint256 hash) { function hashLeftRight(uint256 _left, uint256 _right) public pure returns (uint256 hash) {
// those checks should never trigger in practice, because they're already performed by the snark verifier
// added for convenience if someone decides to call this function directly
require(_left < FIELD_SIZE, "_left should be inside the field"); require(_left < FIELD_SIZE, "_left should be inside the field");
require(_right < FIELD_SIZE, "_right should be inside the field"); require(_right < FIELD_SIZE, "_right should be inside the field");
uint256 R = _left; uint256 R = _left;
@ -90,6 +93,9 @@ contract MerkleTreeWithHistory {
return nextIndex - 1; return nextIndex - 1;
} }
/**
@dev Whether the root is present in the root history
*/
function isKnownRoot(uint256 _root) public view returns(bool) { function isKnownRoot(uint256 _root) public view returns(bool) {
if (_root == 0) { if (_root == 0) {
return false; return false;
@ -123,6 +129,9 @@ contract MerkleTreeWithHistory {
// } while (i != currentRootIndex); // } while (i != currentRootIndex);
} }
/**
@dev Returns the last root
*/
function getLastRoot() public view returns(uint256) { function getLastRoot() public view returns(uint256) {
return roots[currentRootIndex]; return roots[currentRootIndex];
} }

View File

@ -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;
@ -42,8 +41,9 @@ 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 _denomination transfer amount for each deposit
@param _merkleTreeHeight the height of deposits' Merkle Tree @param _merkleTreeHeight the height of deposits' Merkle Tree
@param _operator operator address (see operator above) @param _operator operator address (see operator comment above)
*/ */
constructor( constructor(
IVerifier _verifier, IVerifier _verifier,
@ -75,7 +75,7 @@ contract Mixer is MerkleTreeWithHistory {
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