This is the monorepo for all code and documentation for a noncustodial Ethereum mixer. Try it at micromix.app.
Join the Telegram group to discuss.
A mixer moves ETH or ERC20 tokens from one address to another in a way that nobody except the sender can know for sure that these addresses are linked. This mixer lets a user deposit fixed amounts of ETH into a contract, and when the pool is large enough, anonymously submit zero-knowledge proofs which show that the submitter had previously made a deposit, thus authorising the contract to release funds to the recipient.
As a transaction relayer pays the gas of this transaction, there is no certain on-chain connection between the sender and recipient. Although this relayer is centralised, the mixer is noncustodial and no third party can exit with users' funds.
A technical specification of the mixer is here Implementation feature are listed here .
This mixer is highly experimental and not yet audited. Do not use it to mix real funds yet. It have been tested successfully on Ganache, Kovan ETH, Ropsten ETH, Arbitrum ETH. Get Kovan ETH from a faucet here or here.
The current version of this mixer is a simple MVP for desktop Chrome, Brave, or Firefox. You should also have MetaMask installed, and some Kovan ETH. By default you need at least 0.11 KETH to mix 0.1 ETH, and 20 Kovan DAI and 0.01 ETH to mix Kovan DAI. You can generate Kovan DAI using MakerDAO's CDP creation tool here.
It has the following features:
-
A user interface which allows:
-
One deposit per day.
-
One-click withdrawal once UTC midnight has passed.
-
Immediate self-withdrawals in case the user wants their funds back at the cost of privacy.
-
Immediate withdraw requests if the user wishes the operator to mix the funds immediately, which also comes at the cost of some privacy.
-
-
A backend server with one JSON-RPC 2.0 endpoint (deprecated and replaced with the generic Surrogeth agent),
mixer_mix()
, which:- Accepts, verifies, and submits a zk-SNARK proof (generated in the user's browser) to the mixer contract.
-
Ethereum contracts:
-
The Semaphore zero-knowledge signalling system as a base layer.
-
A Mixer contract with functions which
-
Accepts ETH or ERC20 token deposits.
-
Accepts mix requests. Each request comprises of a zk-SNARK proof that a deposit had been made in the past and has not already been claimed. If the proof is valid, it transfers funds to the recipient and takes an operator's fee.
-
Allows the operator to withdraw all accurred fees.
-
-
A MixerRegistry contract that can deploy Mixer and Semaphore contract
-
A ForwarderRegistryERC20 contract that is used by the Surrogeth deamon to register globaly and to get statistic on usage
-
Gas costs after the Istanbul network upgrade is currently 1.2 million per deposit and 378k to 420k per withdrawal. The gas cost for each withdrawal (before Istanbul) is 886k.
-
These instructions have been tested with Debian 4.19 and Node v15 and v16
Clone this repository and its semaphore
, libsemaphore
and surrogeth
submodule:
git clone https://github.com/jrastit/mixer.git
cd mixer
git submodule update --init
Download the circuit, keys, and verifier contract. Doing this instead of generating your own keys will save you about 20 minutes. Note that these are not for production use as there is no guarantee that the toxic waste was discarded.
./scripts/downloadSnarks.sh
Install dependencies for the libsemaphore submodule:
cd libsemaphore && \
npm i
# if you are still in libsemaphore
cd ../
Install dependencies for the Surrogeth submodule:
cd surrogeth/client && \
npm i
# if you are still in surrogeth
cd ../../
cd surrogeth/surrogethd && \
npm i
# if you are still in surrogeth
cd ../../
If you want to use other network than ganache
Create a file named kovanPrivateKeys.json
(or a name of your choice if you
modify the config) in the mixer/key directory or for more security
in a location outside this repository with a private key which will serve as
the operator's hot wallet.
You can copy it from /mixer/key/ganachePrivateKey.json
Don't use any of this key in production
Only the first 3 values are used for testing
[
"0xaa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7",
"0x0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4",
"0x8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5"
]
Copy config/config.example.yaml
to config/local-dev.yaml
to and modify
it as such:
-
Change
key/kovanPrivateKeys.json
to the absolute path to thekovanPrivateKeys.json
file you just created if not in the contracts directory. -
If you want to test only on ganache, put disalbe : true on all other network (kovan, ... ) Or if you want to run the test, in config : ln -s local-test.yaml local-dev.yaml
npm i && \
npm run bootstrap && \
npm run build
Run ganache with screen
# Assuming you are in mixer/
npm run screen-ganache
Or run it in a new terminal to see the output (let it run and open a new terminal)
# Assuming you are in mixer/
npm run ganache
Clean contract deployed cache (if already deployed before with ganache):
# Assuming you are in mixer/
npm run clean-cache
Deploy the contracts:
# Assuming you are in mixer/
npm run deploy
Config surrogeth from deployed contracts
Autoconfig surrogeth
# Assuming you are in mixer/
npm run surrogeth-info
Run the surrogeth
with screen
# Assuming you are in mixer/
npm run screen-surrogeth
Or in another terminal, run surrogeth:
# Assuming you are in mixer/
npm run surrogeth
Run semaphore
server with screen
# Assuming you are in mixer/
npm run screen-semaphore
Or in annother terminal launch a HTTP server to serve the zk-SNARK content:
# Assuming you are in mixer/
npm run semahpore
You can now run the frontend at http://localhost:1234. Using screen
# Assuming you are in mixer/
npm run screen-frontend
in the terminal
# Assuming you are in mixer/
npm run frontend
To check the status of screen : screen -ls To check a running screen : screen -r MixerFrontend (and then to quit without killing it Ctrl + a / Ctrl + d)
To automatically compile the TypeScript source code whenever you change it,
first make sure that you have npm run watch
running in a terminal. For
instance, while you edit backend/ts/index.ts
, have a terminal open at
backend/
and then run npm run watch
.
If you use a terminal multiplexer like tmux
, your screen might now look like this:
Clockwise from top right:
- Ganache (
npm run ganache
) - Deployed contracts (
npm run deploy
) - Frontend (
npm run frontend
) - Semaphore (
npm run semaphore
) - Surrogeth (
npm run surrogeth
)
etcd
v3.3.13- The backend server requires an
etcd
server to lock the account nonce of its hot wallet.
- The backend server requires an
frontend:
enableBackend: true
Run etcd
with screen
screen -S etcd -d -m etcd
Or in another terminal, run etcd
:
etcd
Run the backend
with screen
# Assuming you are in mixer/
npm run screen-backend
Or in another terminal, run the backend:
# Assuming you are in mixer/
npm run backend
In the mixer/contracts/
directory (after starting ganache and deployed the contracts):
- Modify the config file if needed in
config/local-test.yaml
you can setdisable:true
to disable some networks in the test - Run
npm run screen-ganache
if you are testing the ganache network - Run
npm run clean-cache
to reset contract ganache cache - Run
npm run deploy
to deploy contract - Run
npm run surrogeth-info
to configure surrogeth for testing - Run
npm run screen-surrogeth
to run surrogeth agent for testing - Run
npm run test
to run the test suite
It will run for all enabled network in config to run only specific network and token
add -- --network=ganache --token=eth
In the mixer/backend/
directory (after starting ganache and deployed the contracts):
- Run
npm run test
Check docker configuration file in config/docker.yaml
and docker/docker-compose.yml
To build the image Run:
npm run docker-build
To run the image that will deploy the frontent on port 1235 by default http://localhost:1235/
:
npm run docker-start
To unload the image:
npm run docker-stop
This will produce the following images and containers (edited for brevity):
REPOSITORY TAG SIZE
docker_mixer-frontend latest 37.1MB
mixer-base latest 1.44GB
mixer-build latest 2.32GB
nginx 1.17.1-alpine 20.6MB
node 16-buster 20.6MB
CONTAINER ID IMAGE COMMAND PORTS NAMES
............ docker_mixer-frontend "/bin/sh -c 'nginx -…" 80/tcp, 0.0.0.0:1235->8001/tcp mixer-frontend
In contrast, the local instances run via npm run watch
in
frontend/
and npm run server
in backend
respectively use
config/local-dev.yaml
.
frontend/
: source code for the UIbackend/
: source code for the backend deprecated and replaced with surrogethcontracts/
: source code for mixer contracts and testssemaphore/
: a submodule for the Semaphore codelibsemaphore/
: a submodule for the libsemaphoresurrogeth/
: a submodule for the Surrogeth agent
See the frontend documentation here.
Each PR should contain a clear description of the feature it adds or problem it solves (the why), and walk the user through a summary of how it solves it.
Each PR should also add to the unit and/or integration tests as appropriate.
Add at the end of ~/.profile or run it in your terminal to setup the path
export PATH=~/.npm-global/bin:$PATH
export N_PREFIX=$HOME/.npm-global
Activate change in profile:
. ~/.profile
Install npm (need any node version) you may use the one already present on the system.
wget https://nodejs.org/dist/v14.15.4/node-v14.15.4-linux-x64.tar.xz
tar -xf node-v14.15.4-linux-x64.tar.xz
export PATH=$PATH:.
cd node-v14.15.4-linux-x64/bin
npm config set prefix '~/.npm-global'
Install n (Package manager for node) and node x.x.x
npm i -g n
n x.x.x
Clean not needed version
cd ~/
rm -rf node-v14.15.4-linux-x64.tar.xz node-v14.15.4-linux-x64
Verify
npm -v
#x.x.x
node -v
#v11.14.0
to generate the circuit in a teminal with node 11.14.0
#Check the version of node
node -v
#v11.14.0
cd semaphore/semaphorejs && \
npm i && \
cd scripts && ./build_snarks.sh
# if you are still in semaphore scripts
cd ../../../