mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
update
This commit is contained in:
parent
4122e1e90c
commit
516d599502
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
node_modules
|
||||
build
|
||||
cache
|
||||
artifacts
|
||||
|
@ -1,4 +1,4 @@
|
||||
include "../node_modules/circomlib/circuits/mimcsponge.circom";
|
||||
include "../node_modules/circomlib/circuits/poseidon.circom";
|
||||
|
||||
// Computes MiMC([left, right])
|
||||
template HashLeftRight() {
|
||||
@ -6,11 +6,10 @@ template HashLeftRight() {
|
||||
signal input right;
|
||||
signal output hash;
|
||||
|
||||
component hasher = MiMCSponge(2, 1);
|
||||
hasher.ins[0] <== left;
|
||||
hasher.ins[1] <== right;
|
||||
hasher.k <== 0;
|
||||
hash <== hasher.outs[0];
|
||||
component hasher = Poseidon(2);
|
||||
hasher.inputs[0] <== left;
|
||||
hasher.inputs[1] <== right;
|
||||
hash <== hasher.out;
|
||||
}
|
||||
|
||||
// if s == 0 returns [in[0], in[1]]
|
||||
|
@ -121,4 +121,4 @@ template Transaction(levels, zeroLeaf) {
|
||||
}
|
||||
}
|
||||
|
||||
component main = Transaction(5, 16923532097304556005972200564242292693309333953544141029519619077135960040221);
|
||||
component main = Transaction(5, 11850551329423159860688778991827824730037759162201783566284850822760196767874);
|
||||
|
@ -1,17 +1,15 @@
|
||||
include "../node_modules/circomlib/circuits/pointbits.circom";
|
||||
include "../node_modules/circomlib/circuits/compconstant.circom";
|
||||
include "../node_modules/circomlib/circuits/mimcsponge.circom";
|
||||
include "../node_modules/circomlib/circuits/poseidon.circom";
|
||||
|
||||
|
||||
template Keypair() {
|
||||
signal input privateKey;
|
||||
signal output publicKey;
|
||||
|
||||
component hasher = MiMCSponge(1, 1);
|
||||
hasher.ins[0] <== privateKey;
|
||||
hasher.k <== 0;
|
||||
|
||||
publicKey <== hasher.outs[0];
|
||||
component hasher = Poseidon(1);
|
||||
hasher.inputs[0] <== privateKey;
|
||||
publicKey <== hasher.out;
|
||||
}
|
||||
|
||||
template TransactionHasher() {
|
||||
@ -21,13 +19,11 @@ template TransactionHasher() {
|
||||
|
||||
signal output commitment;
|
||||
|
||||
component hasher = MiMCSponge(3, 1);
|
||||
hasher.ins[0] <== amount;
|
||||
hasher.ins[1] <== blinding;
|
||||
hasher.ins[2] <== publicKey;
|
||||
hasher.k <== 0;
|
||||
|
||||
commitment <== hasher.outs[0];
|
||||
component hasher = Poseidon(3);
|
||||
hasher.inputs[0] <== amount;
|
||||
hasher.inputs[1] <== blinding;
|
||||
hasher.inputs[2] <== publicKey;
|
||||
commitment <== hasher.out;
|
||||
}
|
||||
|
||||
template NullifierHasher() {
|
||||
@ -37,11 +33,9 @@ template NullifierHasher() {
|
||||
|
||||
signal output nullifier;
|
||||
|
||||
component hasher = MiMCSponge(3, 1);
|
||||
hasher.ins[0] <== commitment;
|
||||
hasher.ins[1] <== merklePath;
|
||||
hasher.ins[2] <== privateKey;
|
||||
hasher.k <== 0;
|
||||
|
||||
nullifier <== hasher.outs[0];
|
||||
component hasher = Poseidon(3);
|
||||
hasher.inputs[0] <== commitment;
|
||||
hasher.inputs[1] <== merklePath;
|
||||
hasher.inputs[2] <== privateKey;
|
||||
nullifier <== hasher.out;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// https://tornado.cash
|
||||
/*
|
||||
* d888888P dP a88888b. dP
|
||||
@ -9,12 +10,12 @@
|
||||
* ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.8;
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; // todo: maybe remove?
|
||||
|
||||
contract IVerifier {
|
||||
function verifyProof(bytes memory _proof, uint256[10] memory _input) public returns(bool);
|
||||
interface IVerifier {
|
||||
function verifyProof(bytes memory _proof, uint256[10] memory _input) external returns(bool);
|
||||
}
|
||||
|
||||
contract TornadoPool is ReentrancyGuard {
|
||||
@ -78,11 +79,11 @@ contract TornadoPool is ReentrancyGuard {
|
||||
require(msg.value == uint256(extAmount), "Incorrect amount of ETH sent on deposit");
|
||||
} else {
|
||||
require(msg.value == 0, "Sent ETH amount should be 0 for withdrawal");
|
||||
transfer(_recipient, uint256(-extAmount));
|
||||
_recipient.transfer(uint256(-extAmount));
|
||||
}
|
||||
|
||||
if (_fee > 0) {
|
||||
transfer(_relayer, _fee);
|
||||
_recipient.transfer(_fee);
|
||||
}
|
||||
|
||||
// todo enforce currentCommitmentIndex value in snark
|
||||
@ -105,23 +106,18 @@ contract TornadoPool is ReentrancyGuard {
|
||||
}
|
||||
}
|
||||
|
||||
function transfer(address payable to, uint256 amount) internal {
|
||||
(bool success, ) = to.call.value(amount)("");
|
||||
require(success, "payment did not go through");
|
||||
}
|
||||
|
||||
/** @dev whether a note is already spent */
|
||||
function isSpent(bytes32 _nullifierHash) public view returns(bool) {
|
||||
return nullifierHashes[_nullifierHash];
|
||||
}
|
||||
|
||||
/** @dev whether an array of notes is already spent */
|
||||
function isSpentArray(bytes32[] calldata _nullifierHashes) external view returns(bool[] memory spent) {
|
||||
spent = new bool[](_nullifierHashes.length);
|
||||
for(uint i = 0; i < _nullifierHashes.length; i++) {
|
||||
if (isSpent(_nullifierHashes[i])) {
|
||||
spent[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// /** @dev whether an array of notes is already spent */
|
||||
// function isSpentArray(bytes32[] calldata _nullifierHashes) external view returns(bool[] memory spent) {
|
||||
// spent = new bool[](_nullifierHashes.length);
|
||||
// for(uint i = 0; i < _nullifierHashes.length; i++) {
|
||||
// if (isSpent(_nullifierHashes[i])) {
|
||||
// spent[i] = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
../build/circuits/Verifier.sol
|
||||
../artifacts/circuits/Verifier.sol
|
@ -4,7 +4,7 @@ require('dotenv').config()
|
||||
|
||||
const config = {
|
||||
solidity: {
|
||||
version: '0.5.10',
|
||||
version: '0.6.12',
|
||||
settings: {
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
@ -13,22 +13,14 @@ const config = {
|
||||
},
|
||||
},
|
||||
networks: {
|
||||
hardhat: {
|
||||
gasPrice: 0,
|
||||
chainId: 1,
|
||||
forking: {
|
||||
url: process.env.ETH_RPC,
|
||||
blockNumber: 12197930,
|
||||
},
|
||||
},
|
||||
goerli: {
|
||||
url: process.env.ETH_RPC,
|
||||
accounts: process.env.PRIVATE_KEY
|
||||
? [process.env.PRIVATE_KEY]
|
||||
: {
|
||||
mnemonic: 'test test test test test test test test test test test junk',
|
||||
},
|
||||
},
|
||||
// goerli: {
|
||||
// url: process.env.ETH_RPC,
|
||||
// accounts: process.env.PRIVATE_KEY
|
||||
// ? [process.env.PRIVATE_KEY]
|
||||
// : {
|
||||
// mnemonic: 'test test test test test test test test test test test junk',
|
||||
// },
|
||||
// },
|
||||
},
|
||||
mocha: {
|
||||
timeout: 600000000,
|
||||
|
@ -1,201 +0,0 @@
|
||||
const jsStorage = require('./storage')
|
||||
const hasherImpl = require('./mimc')
|
||||
|
||||
class MerkleTree {
|
||||
|
||||
constructor(n_levels, defaultElements, prefix, storage, hasher) {
|
||||
this.prefix = prefix
|
||||
this.storage = storage || new jsStorage()
|
||||
this.hasher = hasher || new hasherImpl()
|
||||
this.n_levels = n_levels
|
||||
this.zero_values = []
|
||||
this.totalElements = 0
|
||||
|
||||
let current_zero_value = '21663839004416932945382355908790599225266501822907911457504978515578255421292'
|
||||
this.zero_values.push(current_zero_value)
|
||||
for (let i = 0; i < n_levels; i++) {
|
||||
current_zero_value = this.hasher.hash(i, current_zero_value, current_zero_value)
|
||||
this.zero_values.push(
|
||||
current_zero_value.toString(),
|
||||
)
|
||||
}
|
||||
if (defaultElements) {
|
||||
let level = 0
|
||||
this.totalElements = defaultElements.length
|
||||
defaultElements.forEach((element, i) => {
|
||||
this.storage.put(MerkleTree.index_to_key(prefix, level, i), element)
|
||||
})
|
||||
level++
|
||||
let numberOfElementsInLevel = Math.ceil(defaultElements.length / 2)
|
||||
for (level; level <= this.n_levels; level++) {
|
||||
for(let i = 0; i < numberOfElementsInLevel; i++) {
|
||||
const leftKey = MerkleTree.index_to_key(prefix, level - 1, 2 * i)
|
||||
const rightKey = MerkleTree.index_to_key(prefix, level - 1, 2 * i + 1)
|
||||
|
||||
const left = this.storage.get(leftKey)
|
||||
const right = this.storage.get_or_element(rightKey, this.zero_values[level - 1])
|
||||
|
||||
const subRoot = this.hasher.hash(null, left, right)
|
||||
this.storage.put(MerkleTree.index_to_key(prefix, level, i), subRoot)
|
||||
}
|
||||
numberOfElementsInLevel = Math.ceil(numberOfElementsInLevel / 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static index_to_key(prefix, level, index) {
|
||||
const key = `${prefix}_tree_${level}_${index}`
|
||||
return key
|
||||
}
|
||||
|
||||
async root() {
|
||||
let root = await this.storage.get_or_element(
|
||||
MerkleTree.index_to_key(this.prefix, this.n_levels, 0),
|
||||
this.zero_values[this.n_levels],
|
||||
)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
async path(index) {
|
||||
class PathTraverser {
|
||||
constructor(prefix, storage, zero_values) {
|
||||
this.prefix = prefix
|
||||
this.storage = storage
|
||||
this.zero_values = zero_values
|
||||
this.path_elements = []
|
||||
this.path_index = []
|
||||
}
|
||||
|
||||
async handle_index(level, element_index, sibling_index) {
|
||||
const sibling = await this.storage.get_or_element(
|
||||
MerkleTree.index_to_key(this.prefix, level, sibling_index),
|
||||
this.zero_values[level],
|
||||
)
|
||||
this.path_elements.push(sibling)
|
||||
this.path_index.push(element_index % 2)
|
||||
}
|
||||
}
|
||||
index = Number(index)
|
||||
let traverser = new PathTraverser(this.prefix, this.storage, this.zero_values)
|
||||
const root = await this.storage.get_or_element(
|
||||
MerkleTree.index_to_key(this.prefix, this.n_levels, 0),
|
||||
this.zero_values[this.n_levels],
|
||||
)
|
||||
|
||||
const element = await this.storage.get_or_element(
|
||||
MerkleTree.index_to_key(this.prefix, 0, index),
|
||||
this.zero_values[0],
|
||||
)
|
||||
|
||||
await this.traverse(index, traverser)
|
||||
return {
|
||||
root,
|
||||
path_elements: traverser.path_elements,
|
||||
path_index: traverser.path_index,
|
||||
element
|
||||
}
|
||||
}
|
||||
|
||||
async update(index, element, insert = false) {
|
||||
if (!insert && index >= this.totalElements) {
|
||||
throw Error('Use insert method for new elements.')
|
||||
} else if(insert && index < this.totalElements) {
|
||||
throw Error('Use update method for existing elements.')
|
||||
}
|
||||
try {
|
||||
class UpdateTraverser {
|
||||
constructor(prefix, storage, hasher, element, zero_values) {
|
||||
this.prefix = prefix
|
||||
this.current_element = element
|
||||
this.zero_values = zero_values
|
||||
this.storage = storage
|
||||
this.hasher = hasher
|
||||
this.key_values_to_put = []
|
||||
}
|
||||
|
||||
async handle_index(level, element_index, sibling_index) {
|
||||
if (level == 0) {
|
||||
this.original_element = await this.storage.get_or_element(
|
||||
MerkleTree.index_to_key(this.prefix, level, element_index),
|
||||
this.zero_values[level],
|
||||
)
|
||||
}
|
||||
const sibling = await this.storage.get_or_element(
|
||||
MerkleTree.index_to_key(this.prefix, level, sibling_index),
|
||||
this.zero_values[level],
|
||||
)
|
||||
let left, right
|
||||
if (element_index % 2 == 0) {
|
||||
left = this.current_element
|
||||
right = sibling
|
||||
} else {
|
||||
left = sibling
|
||||
right = this.current_element
|
||||
}
|
||||
|
||||
this.key_values_to_put.push({
|
||||
key: MerkleTree.index_to_key(this.prefix, level, element_index),
|
||||
value: this.current_element,
|
||||
})
|
||||
this.current_element = this.hasher.hash(level, left, right)
|
||||
}
|
||||
}
|
||||
let traverser = new UpdateTraverser(
|
||||
this.prefix,
|
||||
this.storage,
|
||||
this.hasher,
|
||||
element,
|
||||
this.zero_values
|
||||
)
|
||||
|
||||
await this.traverse(index, traverser)
|
||||
traverser.key_values_to_put.push({
|
||||
key: MerkleTree.index_to_key(this.prefix, this.n_levels, 0),
|
||||
value: traverser.current_element,
|
||||
})
|
||||
|
||||
await this.storage.put_batch(traverser.key_values_to_put)
|
||||
} catch(e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async insert(element) {
|
||||
const index = this.totalElements
|
||||
await this.update(index, element, true)
|
||||
this.totalElements++
|
||||
}
|
||||
|
||||
// todo it can be mode optimal
|
||||
async insertPair(first, second) {
|
||||
await insert(first)
|
||||
await insert(second)
|
||||
}
|
||||
|
||||
async traverse(index, handler) {
|
||||
let current_index = index
|
||||
for (let i = 0; i < this.n_levels; i++) {
|
||||
let sibling_index = current_index
|
||||
if (current_index % 2 == 0) {
|
||||
sibling_index += 1
|
||||
} else {
|
||||
sibling_index -= 1
|
||||
}
|
||||
await handler.handle_index(i, current_index, sibling_index)
|
||||
current_index = Math.floor(current_index / 2)
|
||||
}
|
||||
}
|
||||
|
||||
getIndexByElement(element) {
|
||||
for(let i = this.totalElements - 1; i >= 0; i--) {
|
||||
const elementFromTree = this.storage.get(MerkleTree.index_to_key(this.prefix, 0, i))
|
||||
if (elementFromTree === element) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MerkleTree
|
17
lib/mimc.js
17
lib/mimc.js
@ -1,17 +0,0 @@
|
||||
const circomlib = require('circomlib')
|
||||
const mimcsponge = circomlib.mimcsponge
|
||||
const snarkjs = require('snarkjs')
|
||||
|
||||
const bigInt = snarkjs.bigInt
|
||||
|
||||
class MimcSpongeHasher {
|
||||
hash(level, left, right) {
|
||||
return mimcsponge.multiHash([bigInt(left), bigInt(right)]).toString()
|
||||
}
|
||||
|
||||
hashArray(items) {
|
||||
return mimcsponge.multiHash(items.map(item => bigInt(item))).toString()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MimcSpongeHasher
|
@ -1,39 +0,0 @@
|
||||
|
||||
|
||||
class JsStorage {
|
||||
constructor() {
|
||||
this.db = {}
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return this.db[key]
|
||||
}
|
||||
|
||||
get_or_element(key, defaultElement) {
|
||||
const element = this.db[key]
|
||||
if (element === undefined) {
|
||||
return defaultElement
|
||||
} else {
|
||||
return element
|
||||
}
|
||||
}
|
||||
|
||||
put(key, value) {
|
||||
if (key === undefined || value === undefined) {
|
||||
throw Error('key or value is undefined')
|
||||
}
|
||||
this.db[key] = value
|
||||
}
|
||||
|
||||
del(key) {
|
||||
delete this.db[key]
|
||||
}
|
||||
|
||||
put_batch(key_values) {
|
||||
key_values.forEach(element => {
|
||||
this.db[element.key] = element.value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = JsStorage
|
@ -1,6 +0,0 @@
|
||||
/* global artifacts */
|
||||
const Verifier = artifacts.require('Verifier')
|
||||
|
||||
module.exports = function(deployer) {
|
||||
deployer.deploy(Verifier)
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/* global artifacts */
|
||||
const Verifier = artifacts.require('Verifier')
|
||||
const TornadoPool = artifacts.require('TornadoPool')
|
||||
const MERKLE_TREE_HEIGHT = 5
|
||||
const MerkleTree = require('../lib/merkleTree')
|
||||
const { bigInt } = require('snarkjs')
|
||||
const toHex = (number, length = 32) => '0x' + (number instanceof Buffer ? number.toString('hex') : bigInt(number).toString(16)).padStart(length * 2, '0')
|
||||
|
||||
|
||||
module.exports = function(deployer, network, accounts) {
|
||||
return deployer.then(async () => {
|
||||
const tree = new MerkleTree(MERKLE_TREE_HEIGHT)
|
||||
const root = await tree.root()
|
||||
const verifier = await Verifier.deployed()
|
||||
|
||||
const tornado = await deployer.deploy(TornadoPool, verifier.address, toHex(root))
|
||||
console.log('TornadoPool\'s address ', tornado.address)
|
||||
})
|
||||
}
|
22
package.json
22
package.json
@ -7,13 +7,11 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build:circuit:compile": "npx circom circuits/transaction.circom -o build/circuits/transaction.json && npx snarkjs info -c build/circuits/transaction.json",
|
||||
"build:circuit:setup": "npx snarkjs setup --protocol groth -c build/circuits/transaction.json --pk build/circuits/transaction_proving_key.json --vk build/circuits/transaction_verification_key.json",
|
||||
"build:circuit:bin": "node node_modules/websnark/tools/buildpkey.js -i build/circuits/transaction_proving_key.json -o build/circuits/transaction_proving_key.bin",
|
||||
"build:circuit:contract": "npx snarkjs generateverifier -v build/circuits/Verifier.sol --vk build/circuits/transaction_verification_key.json",
|
||||
"build:circuit": "mkdir -p build/circuits && npm run build:circuit:compile && npm run build:circuit:setup && npm run build:circuit:bin && npm run build:circuit:contract",
|
||||
"build:circuit": "./scripts/buildCircuit.sh transaction",
|
||||
"build:contract": "npx hardhat compile",
|
||||
"build": "npm run build:circuit && npm run build:contract",
|
||||
"migrate": "npx hardhat run scripts/deploy.js --network localhost",
|
||||
"start": "node ./src/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@ -21,15 +19,19 @@
|
||||
"dependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||
"@openzeppelin/contracts": "^2.5.0",
|
||||
"@openzeppelin/contracts": "^3.4.0",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"circom": "0.0.35",
|
||||
"circomlib": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc",
|
||||
"circom": "0.5.42",
|
||||
"circom_runtime": "^0.1.12",
|
||||
"circomlib": "git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1",
|
||||
"dotenv": "^10.0.0",
|
||||
"ethereum-waffle": "^3.2.0",
|
||||
"ethers": "^5.0.0",
|
||||
"ffiasm": "^0.1.1",
|
||||
"ffjavascript": "^0.2.35",
|
||||
"fixed-merkle-tree": "^0.5.0",
|
||||
"hardhat": "^2.3.0",
|
||||
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
|
||||
"websnark": "git+https://github.com/tornadocash/websnark.git#2041cfa5fa0b71cd5cca9022a4eeea4afe28c9f7"
|
||||
"snarkjs": "^0.3.57",
|
||||
"tmp-promise": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
6
scripts/buildCircuit.sh
Executable file
6
scripts/buildCircuit.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash -e
|
||||
mkdir -p artifacts/circuits
|
||||
npx circom -v -r artifacts/circuits/$1.r1cs -w artifacts/circuits/$1.wasm -s artifacts/circuits/$1.sym circuits/$1.circom
|
||||
zkutil setup -c artifacts/circuits/$1.r1cs -p artifacts/circuits/$1.params
|
||||
zkutil generate-verifier -p artifacts/circuits/$1.params -v artifacts/circuits/Verifier.sol
|
||||
npx snarkjs info -r artifacts/circuits/$1.r1cs
|
35
scripts/deploy.js
Normal file
35
scripts/deploy.js
Normal file
@ -0,0 +1,35 @@
|
||||
const { ethers } = require('hardhat')
|
||||
|
||||
const MERKLE_TREE_HEIGHT = 5
|
||||
const MerkleTree = require('fixed-merkle-tree')
|
||||
const { poseidon } = require('circomlib')
|
||||
const poseidonHash = (items) => ethers.BigNumber.from(poseidon(items).toString())
|
||||
const poseidonHash2 = (a, b) => poseidonHash([a, b])
|
||||
|
||||
const toFixedHex = (number, length = 32) =>
|
||||
'0x' +
|
||||
(number instanceof Buffer
|
||||
? number.toString('hex')
|
||||
: ethers.BigNumber.from(number).toHexString().slice(2)
|
||||
).padStart(length * 2, '0')
|
||||
|
||||
async function main() {
|
||||
const Verifier = await ethers.getContractFactory('Verifier')
|
||||
const verifier = await Verifier.deploy()
|
||||
await verifier.deployed()
|
||||
console.log(`verifier: ${verifier.address}`)
|
||||
|
||||
const tree = new MerkleTree(MERKLE_TREE_HEIGHT, [], { hashFunction: poseidonHash2 })
|
||||
const root = await tree.root()
|
||||
|
||||
const Pool = await ethers.getContractFactory('TornadoPool')
|
||||
const tornado = await Pool.deploy(verifier.address, toFixedHex(root))
|
||||
console.log("TornadoPool's address ", tornado.address)
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
193
src/index.js
193
src/index.js
@ -1,56 +1,38 @@
|
||||
/* eslint-disable no-console */
|
||||
const MerkleTree = require('../lib/merkleTree')
|
||||
const MerkleTree = require('fixed-merkle-tree')
|
||||
const fs = require('fs')
|
||||
const { bigInt, stringifyBigInts } = require('snarkjs')
|
||||
const crypto = require('crypto')
|
||||
const Hasher = require('../lib/mimc')
|
||||
const { poseidon } = require('circomlib')
|
||||
const Web3 = require('web3')
|
||||
const buildGroth16 = require('websnark/src/groth16')
|
||||
const websnarkUtils = require('websnark/src/utils')
|
||||
|
||||
let contract, web3, circuit, proving_key, groth16
|
||||
const hasher = new Hasher()
|
||||
|
||||
// console.log(hasher.hashArray(['21663839004416932945382355908790599225266501822907911457504978515578255421292', '21663839004416932945382355908790599225266501822907911457504978515578255421292']))
|
||||
const { ethers } = require('hardhat')
|
||||
const { BigNumber } = ethers
|
||||
const { randomBN, bitsToNumber, toFixedHex, toBuffer, poseidonHash, poseidonHash2 } = require('./utils')
|
||||
|
||||
let contract, web3
|
||||
const { prove } = require('./prover')
|
||||
const FIELD_SIZE = '21888242871839275222246405745257275088548364400416034343698204186575808495617'
|
||||
const MERKLE_TREE_HEIGHT = 5
|
||||
const RPC_URL = 'http://localhost:8545'
|
||||
const FIELD_SIZE = '21888242871839275222246405745257275088548364400416034343698204186575808495617'
|
||||
|
||||
/** Generate random number of specified byte length */
|
||||
const rbigint = (nbytes = 31) => bigInt.leBuff2int(crypto.randomBytes(nbytes))
|
||||
|
||||
/** BigNumber to hex string of specified length */
|
||||
const toHex = (number, length = 32) => '0x' + (number instanceof Buffer ? number.toString('hex') : bigInt(number).toString(16)).padStart(length * 2, '0')
|
||||
|
||||
|
||||
function merklePathIndicesToBigint(indexArray) {
|
||||
let result = 0
|
||||
for(let item of indexArray.slice().reverse()) {
|
||||
result = (result << 1) + item
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function fromPrivkey(privkey) {
|
||||
return {
|
||||
privkey,
|
||||
pubkey: hasher.hashArray([privkey]),
|
||||
pubkey: poseidonHash([privkey]),
|
||||
}
|
||||
}
|
||||
|
||||
function randomKeypair() {
|
||||
return fromPrivkey(rbigint())
|
||||
return fromPrivkey(randomBN())
|
||||
}
|
||||
|
||||
function createZeroUtxo(keypair) {
|
||||
return createUtxo(
|
||||
0,
|
||||
rbigint(),
|
||||
randomBN(),
|
||||
keypair.pubkey,
|
||||
keypair.privkey,
|
||||
Array(MERKLE_TREE_HEIGHT).fill(0),
|
||||
Array(MERKLE_TREE_HEIGHT).fill(0)
|
||||
Array(MERKLE_TREE_HEIGHT).fill(0),
|
||||
)
|
||||
}
|
||||
|
||||
@ -58,7 +40,7 @@ function createOutput(amount, pubkey) {
|
||||
if (!pubkey) {
|
||||
throw new Error('no pubkey')
|
||||
}
|
||||
return createUtxo(amount, rbigint(), pubkey)
|
||||
return createUtxo(amount, randomBN(), pubkey)
|
||||
}
|
||||
|
||||
function createInput({ amount, blinding, pubkey, privkey, merklePathIndices, merklePathElements }) {
|
||||
@ -68,9 +50,9 @@ function createInput({ amount, blinding, pubkey, privkey, merklePathIndices, mer
|
||||
/// unsafe function without sanity checks
|
||||
function createUtxo(amount, blinding, pubkey, privkey, merklePathIndices, merklePathElements) {
|
||||
let utxo = { amount, blinding, pubkey, privkey, merklePathIndices, merklePathElements }
|
||||
utxo.commitment = hasher.hashArray([amount, blinding, pubkey])
|
||||
utxo.commitment = poseidonHash([amount, blinding, pubkey])
|
||||
if (privkey) {
|
||||
utxo.nullifier = hasher.hashArray([utxo.commitment, merklePathIndicesToBigint(merklePathIndices), privkey])
|
||||
utxo.nullifier = poseidonHash([utxo.commitment, bitsToNumber(merklePathIndices), privkey])
|
||||
}
|
||||
return utxo
|
||||
}
|
||||
@ -91,16 +73,16 @@ async function buildMerkleTree() {
|
||||
const events = await contract.getPastEvents('NewCommitment', { fromBlock: 0, toBlock: 'latest' })
|
||||
const leaves = events
|
||||
.sort((a, b) => a.returnValues.index - b.returnValues.index) // todo sort by event date
|
||||
.map(e => toHex(e.returnValues.commitment))
|
||||
.map((e) => toFixedHex(e.returnValues.commitment))
|
||||
console.log('leaves', leaves)
|
||||
return new MerkleTree(MERKLE_TREE_HEIGHT, leaves)
|
||||
return new MerkleTree(MERKLE_TREE_HEIGHT, leaves, { hashFunction: poseidonHash2 })
|
||||
}
|
||||
|
||||
async function insertOutput(tree, output) {
|
||||
await tree.insert(output.commitment)
|
||||
let { path_elements, path_index } = await tree.path(tree.totalElements - 1)
|
||||
output.merklePathIndices = path_index
|
||||
output.merklePathElements = path_elements
|
||||
let { pathElements, pathIndices } = await tree.path(tree.elements().length - 1)
|
||||
output.merklePathIndices = pathIndices
|
||||
output.merklePathElements = pathElements
|
||||
}
|
||||
|
||||
async function deposit() {
|
||||
@ -129,37 +111,42 @@ async function deposit() {
|
||||
// data for 2 transaction inputs
|
||||
inAmount: [tx.inputs[0].amount, tx.inputs[1].amount],
|
||||
inBlinding: [tx.inputs[0].blinding, tx.inputs[1].blinding],
|
||||
inPathIndices: [merklePathIndicesToBigint(tx.inputs[0].merklePathIndices), merklePathIndicesToBigint(tx.inputs[1].merklePathIndices)],
|
||||
inPathIndices: [
|
||||
bitsToNumber(tx.inputs[0].merklePathIndices),
|
||||
bitsToNumber(tx.inputs[1].merklePathIndices),
|
||||
],
|
||||
inPathElements: [tx.inputs[0].merklePathElements, tx.inputs[1].merklePathElements],
|
||||
|
||||
// data for 2 transaction outputs
|
||||
outAmount: [tx.outputs[0].amount, tx.outputs[1].amount],
|
||||
outBlinding: [tx.outputs[0].blinding, tx.outputs[1].blinding],
|
||||
outPubkey: [tx.outputs[0].pubkey, tx.outputs[1].pubkey],
|
||||
outPathIndices: merklePathIndicesToBigint(tx.outputs[0].merklePathIndices.slice(1)),
|
||||
outPathElements: tx.outputs[0].merklePathElements.slice(1)
|
||||
outPathIndices: bitsToNumber(tx.outputs[0].merklePathIndices.slice(1)),
|
||||
outPathElements: tx.outputs[0].merklePathElements.slice(1),
|
||||
}
|
||||
|
||||
// console.log('input', JSON.stringify(stringifyBigInts(input)))
|
||||
console.log('DEPOSIT input', input)
|
||||
|
||||
console.log('Generating SNARK proof...')
|
||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
|
||||
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
||||
|
||||
const proof = await prove(input, './artifacts/circuits/transaction')
|
||||
|
||||
const args = [
|
||||
toHex(input.root),
|
||||
toHex(input.newRoot),
|
||||
[toHex(tx.inputs[0].nullifier), toHex(tx.inputs[1].nullifier)],
|
||||
[toHex(tx.outputs[0].commitment), toHex(tx.outputs[1].commitment)],
|
||||
toHex(amount),
|
||||
toHex(input.fee),
|
||||
toHex(input.recipient, 20),
|
||||
toHex(input.relayer, 20),
|
||||
toFixedHex(input.root),
|
||||
toFixedHex(input.newRoot),
|
||||
[toFixedHex(tx.inputs[0].nullifier), toFixedHex(tx.inputs[1].nullifier)],
|
||||
[toFixedHex(tx.outputs[0].commitment), toFixedHex(tx.outputs[1].commitment)],
|
||||
toFixedHex(amount),
|
||||
toFixedHex(input.fee),
|
||||
toFixedHex(input.recipient, 20),
|
||||
toFixedHex(input.relayer, 20),
|
||||
]
|
||||
|
||||
console.log('Sending deposit transaction...')
|
||||
const receipt = await contract.methods.transaction(proof, ...args).send({ value: amount, from: web3.eth.defaultAccount, gas: 1e6 })
|
||||
const receipt = await contract.methods
|
||||
.transaction(proof, ...args)
|
||||
.send({ value: amount, from: web3.eth.defaultAccount, gas: 1e6 })
|
||||
console.log(`Receipt ${receipt.transactionHash}`)
|
||||
return tx.outputs[0]
|
||||
}
|
||||
@ -167,18 +154,22 @@ async function deposit() {
|
||||
async function transact(txOutput) {
|
||||
console.log('txOutput', txOutput)
|
||||
const tree = await buildMerkleTree()
|
||||
console.log('tree', tree)
|
||||
const oldRoot = await tree.root()
|
||||
const keypair = randomKeypair()
|
||||
|
||||
const index = await tree.getIndexByElement(toHex(txOutput.commitment))
|
||||
const index = await tree.indexOf(toFixedHex(txOutput.commitment))
|
||||
console.log('index', index)
|
||||
const { path_elements, path_index } = await tree.path(index)
|
||||
console.log('path_index', path_index)
|
||||
txOutput.merklePathElements = path_elements
|
||||
const { pathElements, pathIndices } = await tree.path(index)
|
||||
console.log('pathIndices', pathIndices)
|
||||
txOutput.merklePathElements = pathElements
|
||||
const input1 = createInput(txOutput)
|
||||
const tx = {
|
||||
inputs: [input1, createZeroUtxo(fromPrivkey(txOutput.privkey))],
|
||||
outputs: [createOutput(txOutput.amount / 4, keypair.pubkey), createOutput(txOutput.amount * 3 / 4, txOutput.pubkey)], // todo shuffle
|
||||
outputs: [
|
||||
createOutput(txOutput.amount / 4, keypair.pubkey),
|
||||
createOutput((txOutput.amount * 3) / 4, txOutput.pubkey),
|
||||
], // todo shuffle
|
||||
}
|
||||
tx.outputs[0].privkey = keypair.privkey
|
||||
tx.outputs[1].privkey = txOutput.privkey
|
||||
@ -202,36 +193,40 @@ async function transact(txOutput) {
|
||||
// data for 2 transaction inputs
|
||||
inAmount: [tx.inputs[0].amount, tx.inputs[1].amount],
|
||||
inBlinding: [tx.inputs[0].blinding, tx.inputs[1].blinding],
|
||||
inPathIndices: [merklePathIndicesToBigint(tx.inputs[0].merklePathIndices), merklePathIndicesToBigint(tx.inputs[1].merklePathIndices)],
|
||||
inPathIndices: [
|
||||
bitsToNumber(tx.inputs[0].merklePathIndices),
|
||||
bitsToNumber(tx.inputs[1].merklePathIndices),
|
||||
],
|
||||
inPathElements: [tx.inputs[0].merklePathElements, tx.inputs[1].merklePathElements],
|
||||
|
||||
// data for 2 transaction outputs
|
||||
outAmount: [tx.outputs[0].amount, tx.outputs[1].amount],
|
||||
outBlinding: [tx.outputs[0].blinding, tx.outputs[1].blinding],
|
||||
outPubkey: [tx.outputs[0].pubkey, tx.outputs[1].pubkey],
|
||||
outPathIndices: merklePathIndicesToBigint(tx.outputs[0].merklePathIndices.slice(1)),
|
||||
outPathElements: tx.outputs[0].merklePathElements.slice(1)
|
||||
outPathIndices: bitsToNumber(tx.outputs[0].merklePathIndices.slice(1)),
|
||||
outPathElements: tx.outputs[0].merklePathElements.slice(1),
|
||||
}
|
||||
|
||||
console.log('TRANSFER input', input)
|
||||
|
||||
console.log('Generating SNARK proof...')
|
||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
|
||||
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
||||
const proof = await prove(input, './artifacts/circuits/transaction')
|
||||
|
||||
const args = [
|
||||
toHex(input.root),
|
||||
toHex(input.newRoot),
|
||||
[toHex(tx.inputs[0].nullifier), toHex(tx.inputs[1].nullifier)],
|
||||
[toHex(tx.outputs[0].commitment), toHex(tx.outputs[1].commitment)],
|
||||
toHex(0),
|
||||
toHex(input.fee),
|
||||
toHex(input.recipient, 20),
|
||||
toHex(input.relayer, 20),
|
||||
toFixedHex(input.root),
|
||||
toFixedHex(input.newRoot),
|
||||
[toFixedHex(tx.inputs[0].nullifier), toFixedHex(tx.inputs[1].nullifier)],
|
||||
[toFixedHex(tx.outputs[0].commitment), toFixedHex(tx.outputs[1].commitment)],
|
||||
toFixedHex(0),
|
||||
toFixedHex(input.fee),
|
||||
toFixedHex(input.recipient, 20),
|
||||
toFixedHex(input.relayer, 20),
|
||||
]
|
||||
|
||||
console.log('Sending transfer transaction...')
|
||||
const receipt = await contract.methods.transaction(proof, ...args).send({ from: web3.eth.defaultAccount, gas: 1e6 })
|
||||
const receipt = await contract.methods
|
||||
.transaction(proof, ...args)
|
||||
.send({ from: web3.eth.defaultAccount, gas: 1e6 })
|
||||
console.log(`Receipt ${receipt.transactionHash}`)
|
||||
return tx.outputs[0]
|
||||
}
|
||||
@ -241,11 +236,11 @@ async function withdraw(txOutput) {
|
||||
const tree = await buildMerkleTree()
|
||||
const oldRoot = await tree.root()
|
||||
|
||||
const index = await tree.getIndexByElement(toHex(txOutput.commitment))
|
||||
const index = await tree.indexOf(toFixedHex(txOutput.commitment))
|
||||
console.log('index', index)
|
||||
const { path_elements, path_index } = await tree.path(index)
|
||||
console.log('path_index', path_index)
|
||||
txOutput.merklePathElements = path_elements
|
||||
const { pathElements, pathIndices } = await tree.path(index)
|
||||
console.log('pathIndices', pathIndices)
|
||||
txOutput.merklePathElements = pathElements
|
||||
const input1 = createInput(txOutput)
|
||||
const fakeKeypair = randomKeypair()
|
||||
const tx = {
|
||||
@ -260,7 +255,7 @@ async function withdraw(txOutput) {
|
||||
newRoot: await tree.root(),
|
||||
inputNullifier: [tx.inputs[0].nullifier, tx.inputs[1].nullifier],
|
||||
outputCommitment: [tx.outputs[0].commitment, tx.outputs[1].commitment],
|
||||
extAmount: bigInt(FIELD_SIZE).sub(bigInt(txOutput.amount)),
|
||||
extAmount: BigNumber.from(FIELD_SIZE).sub(BigNumber.from(txOutput.amount)),
|
||||
fee: 0,
|
||||
recipient: '0xc2Ba33d4c0d2A92fb4f1a07C273c5d21E688Eb48',
|
||||
relayer: 0,
|
||||
@ -271,58 +266,60 @@ async function withdraw(txOutput) {
|
||||
// data for 2 transaction inputs
|
||||
inAmount: [tx.inputs[0].amount, tx.inputs[1].amount],
|
||||
inBlinding: [tx.inputs[0].blinding, tx.inputs[1].blinding],
|
||||
inPathIndices: [merklePathIndicesToBigint(tx.inputs[0].merklePathIndices), merklePathIndicesToBigint(tx.inputs[1].merklePathIndices)],
|
||||
inPathIndices: [
|
||||
bitsToNumber(tx.inputs[0].merklePathIndices),
|
||||
bitsToNumber(tx.inputs[1].merklePathIndices),
|
||||
],
|
||||
inPathElements: [tx.inputs[0].merklePathElements, tx.inputs[1].merklePathElements],
|
||||
|
||||
// data for 2 transaction outputs
|
||||
outAmount: [tx.outputs[0].amount, tx.outputs[1].amount],
|
||||
outBlinding: [tx.outputs[0].blinding, tx.outputs[1].blinding],
|
||||
outPubkey: [tx.outputs[0].pubkey, tx.outputs[1].pubkey],
|
||||
outPathIndices: merklePathIndicesToBigint(tx.outputs[0].merklePathIndices.slice(1)),
|
||||
outPathElements: tx.outputs[0].merklePathElements.slice(1)
|
||||
outPathIndices: bitsToNumber(tx.outputs[0].merklePathIndices.slice(1)),
|
||||
outPathElements: tx.outputs[0].merklePathElements.slice(1),
|
||||
}
|
||||
|
||||
console.log('WITHDRAW input', input)
|
||||
|
||||
console.log('Generating SNARK proof...')
|
||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
|
||||
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
||||
const proof = await prove(input, './artifacts/circuits/transaction')
|
||||
|
||||
const args = [
|
||||
toHex(input.root),
|
||||
toHex(input.newRoot),
|
||||
[toHex(tx.inputs[0].nullifier), toHex(tx.inputs[1].nullifier)],
|
||||
[toHex(tx.outputs[0].commitment), toHex(tx.outputs[1].commitment)],
|
||||
toHex(input.extAmount),
|
||||
toHex(input.fee),
|
||||
toHex(input.recipient, 20),
|
||||
toHex(input.relayer, 20),
|
||||
toFixedHex(input.root),
|
||||
toFixedHex(input.newRoot),
|
||||
[toFixedHex(tx.inputs[0].nullifier), toFixedHex(tx.inputs[1].nullifier)],
|
||||
[toFixedHex(tx.outputs[0].commitment), toFixedHex(tx.outputs[1].commitment)],
|
||||
toFixedHex(input.extAmount),
|
||||
toFixedHex(input.fee),
|
||||
toFixedHex(input.recipient, 20),
|
||||
toFixedHex(input.relayer, 20),
|
||||
]
|
||||
|
||||
console.log('args', args)
|
||||
|
||||
console.log('Sending withdraw transaction...')
|
||||
const receipt = await contract.methods.transaction(proof, ...args).send({ from: web3.eth.defaultAccount, gas: 1e6 })
|
||||
const receipt = await contract.methods
|
||||
.transaction(proof, ...args)
|
||||
.send({ from: web3.eth.defaultAccount, gas: 1e6 })
|
||||
console.log(`Receipt ${receipt.transactionHash}`)
|
||||
|
||||
|
||||
let bal = await web3.eth.getBalance('0xc2Ba33d4c0d2A92fb4f1a07C273c5d21E688Eb48')
|
||||
console.log('balance', bal)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
web3 = new Web3(new Web3.providers.HttpProvider(RPC_URL, { timeout: 5 * 60 * 1000 }), null, { transactionConfirmationBlocks: 1 })
|
||||
circuit = require('../build/circuits/transaction.json')
|
||||
proving_key = fs.readFileSync('../build/circuits/transaction_proving_key.bin').buffer
|
||||
groth16 = await buildGroth16()
|
||||
web3 = new Web3(new Web3.providers.HttpProvider(RPC_URL, { timeout: 5 * 60 * 1000 }), null, {
|
||||
transactionConfirmationBlocks: 1,
|
||||
})
|
||||
netId = await web3.eth.net.getId()
|
||||
const contractData = require('../build/contracts/TornadoPool.json')
|
||||
contract = new web3.eth.Contract(contractData.abi, contractData.networks[netId].address)
|
||||
const contractData = require('../artifacts/contracts/TornadoPool.sol/TornadoPool.json')
|
||||
contract = new web3.eth.Contract(contractData.abi, '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9')
|
||||
web3.eth.defaultAccount = (await web3.eth.getAccounts())[0]
|
||||
|
||||
const txOutput = await deposit()
|
||||
const txOutput1 = await transact(txOutput)
|
||||
await withdraw(txOutput1)
|
||||
|
||||
}
|
||||
|
||||
main()
|
||||
|
41
src/prover.js
Normal file
41
src/prover.js
Normal file
@ -0,0 +1,41 @@
|
||||
const { wtns } = require('snarkjs')
|
||||
const { utils } = require('ffjavascript')
|
||||
|
||||
const fs = require('fs')
|
||||
const tmp = require('tmp-promise')
|
||||
const util = require('util')
|
||||
const exec = util.promisify(require('child_process').exec)
|
||||
|
||||
function stringify() {}
|
||||
|
||||
function prove(input, keyBasePath) {
|
||||
input = utils.stringifyBigInts(input)
|
||||
console.log('input', input)
|
||||
return tmp.dir().then(async (dir) => {
|
||||
dir = dir.path
|
||||
let out
|
||||
|
||||
try {
|
||||
await wtns.debug(
|
||||
utils.unstringifyBigInts(input),
|
||||
`${keyBasePath}.wasm`,
|
||||
`${dir}/witness.wtns`,
|
||||
`${keyBasePath}.sym`,
|
||||
{},
|
||||
console,
|
||||
)
|
||||
const witness = utils.stringifyBigInts(await wtns.exportJson(`${dir}/witness.wtns`))
|
||||
fs.writeFileSync(`${dir}/witness.json`, JSON.stringify(witness, null, 2))
|
||||
|
||||
out = await exec(
|
||||
`zkutil prove -c ${keyBasePath}.r1cs -p ${keyBasePath}.params -w ${dir}/witness.json -r ${dir}/proof.json -o ${dir}/public.json`,
|
||||
)
|
||||
} catch (e) {
|
||||
console.log(out, e)
|
||||
throw e
|
||||
}
|
||||
return '0x' + JSON.parse(fs.readFileSync(`${dir}/proof.json`)).proof
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { prove }
|
44
src/utils.js
Normal file
44
src/utils.js
Normal file
@ -0,0 +1,44 @@
|
||||
const crypto = require('crypto')
|
||||
const ethers = require('ethers')
|
||||
const BigNumber = ethers.BigNumber
|
||||
const { poseidon } = require('circomlib')
|
||||
|
||||
const poseidonHash = (items) => BigNumber.from(poseidon(items).toString())
|
||||
const poseidonHash2 = (a, b) => poseidonHash([a, b])
|
||||
|
||||
/** Generate random number of specified byte length */
|
||||
const randomBN = (nbytes = 31) => BigNumber.from(crypto.randomBytes(nbytes))
|
||||
|
||||
/** BigNumber to hex string of specified length */
|
||||
const toFixedHex = (number, length = 32) =>
|
||||
'0x' +
|
||||
(number instanceof Buffer
|
||||
? number.toString('hex')
|
||||
: BigNumber.from(number).toHexString().slice(2)
|
||||
).padStart(length * 2, '0')
|
||||
|
||||
const toBuffer = (value, length) =>
|
||||
Buffer.from(
|
||||
BigNumber.from(value)
|
||||
.toHexString()
|
||||
.slice(2)
|
||||
.padStart(length * 2, '0'),
|
||||
'hex',
|
||||
)
|
||||
|
||||
function bitsToNumber(bits) {
|
||||
let result = 0
|
||||
for (const item of bits.slice().reverse()) {
|
||||
result = (result << 1) + item
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
randomBN,
|
||||
bitsToNumber,
|
||||
toFixedHex,
|
||||
toBuffer,
|
||||
poseidonHash,
|
||||
poseidonHash2,
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('@truffle/hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
development: {
|
||||
host: "127.0.0.1", // Localhost (default: none)
|
||||
port: 8545, // Standard Ethereum port (default: none)
|
||||
network_id: "*", // Any network (default: none)
|
||||
},
|
||||
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: "0.5.17", // Fetch exact version from solc-bin (default: truffle's version)
|
||||
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
|
||||
settings: { // See the solidity docs for advice about optimization and evmVersion
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 200
|
||||
},
|
||||
//evmVersion: "byzantium"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user