mirror of
https://github.com/tornadocash/tornado-cli.git
synced 2024-10-01 07:15:36 -04:00
init
This commit is contained in:
parent
496680b379
commit
62758b3e61
185
cli.js
185
cli.js
@ -3,41 +3,23 @@
|
|||||||
// Works both in browser and node.js
|
// Works both in browser and node.js
|
||||||
|
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const fs = require('fs')
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const snarkjs = require('snarkjs')
|
|
||||||
const crypto = require('crypto')
|
|
||||||
const circomlib = require('circomlib')
|
|
||||||
const bigInt = snarkjs.bigInt
|
|
||||||
const merkleTree = require('./lib/MerkleTree')
|
|
||||||
const Web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
const buildGroth16 = require('websnark/src/groth16')
|
|
||||||
const websnarkUtils = require('websnark/src/utils')
|
|
||||||
const { toWei, fromWei, toBN, BN } = require('web3-utils')
|
const { toWei, fromWei, toBN, BN } = require('web3-utils')
|
||||||
const config = require('./config')
|
const config = require('./config')
|
||||||
const program = require('commander')
|
const program = require('commander')
|
||||||
const { GasPriceOracle } = require('gas-price-oracle')
|
const { GasPriceOracle } = require('gas-price-oracle')
|
||||||
|
|
||||||
let web3, tornado, mixerContract, tornadoInstance, circuit, proving_key, groth16, erc20, senderAccount, netId
|
const { initialize, createDeposit, generateProof, toHex, rbigint, bigInt } = require('./core')
|
||||||
|
|
||||||
|
let web3, tornado, mixerContract, tornadoInstance, erc20, senderAccount, netId
|
||||||
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY
|
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY
|
||||||
|
|
||||||
/** Whether we are in a browser or node.js */
|
|
||||||
const inBrowser = typeof window !== 'undefined'
|
|
||||||
let isLocalRPC = false
|
let isLocalRPC = false
|
||||||
|
|
||||||
/** Generate random number of specified byte length */
|
|
||||||
const rbigint = (nbytes) => snarkjs.bigInt.leBuff2int(crypto.randomBytes(nbytes))
|
|
||||||
|
|
||||||
/** Compute pedersen hash */
|
|
||||||
const pedersenHash = (data) => circomlib.babyJub.unpackPoint(circomlib.pedersenHash.hash(data))[0]
|
|
||||||
|
|
||||||
/** BigNumber to hex string of specified length */
|
|
||||||
function toHex(number, length = 32) {
|
|
||||||
const str = number instanceof Buffer ? number.toString('hex') : bigInt(number).toString(16)
|
|
||||||
return '0x' + str.padStart(length * 2, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Display ETH account balance */
|
/** Display ETH account balance */
|
||||||
async function printETHBalance({ address, name }) {
|
async function printETHBalance({ address, name }) {
|
||||||
console.log(`${name} ETH balance is`, web3.utils.fromWei(await web3.eth.getBalance(address)))
|
console.log(`${name} ETH balance is`, web3.utils.fromWei(await web3.eth.getBalance(address)))
|
||||||
@ -50,19 +32,6 @@ async function printERC20Balance({ address, name, tokenAddress }) {
|
|||||||
console.log(`${name} Token Balance is`, web3.utils.fromWei(await erc20.methods.balanceOf(address).call()))
|
console.log(`${name} Token Balance is`, web3.utils.fromWei(await erc20.methods.balanceOf(address).call()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create deposit object from secret and nullifier
|
|
||||||
*/
|
|
||||||
function createDeposit({ nullifier, secret }) {
|
|
||||||
const deposit = { nullifier, secret }
|
|
||||||
deposit.preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)])
|
|
||||||
deposit.commitment = pedersenHash(deposit.preimage)
|
|
||||||
deposit.commitmentHex = toHex(deposit.commitment)
|
|
||||||
deposit.nullifierHash = pedersenHash(deposit.nullifier.leInt2Buff(31))
|
|
||||||
deposit.nullifierHex = toHex(deposit.nullifierHash)
|
|
||||||
return deposit
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a deposit
|
* Make a deposit
|
||||||
* @param currency Сurrency
|
* @param currency Сurrency
|
||||||
@ -111,97 +80,17 @@ async function deposit({ currency, amount }) {
|
|||||||
return noteString
|
return noteString
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate merkle tree for a deposit.
|
|
||||||
* Download deposit events from the tornado, reconstructs merkle tree, finds our deposit leaf
|
|
||||||
* in it and generates merkle proof
|
|
||||||
* @param deposit Deposit object
|
|
||||||
*/
|
|
||||||
async function generateMerkleProof(deposit) {
|
|
||||||
let leafIndex = -1
|
|
||||||
// Get all deposit events from smart contract and assemble merkle tree from them
|
|
||||||
const events = await mixerContract.getPastEvents('Deposit', {
|
|
||||||
fromBlock: 0,
|
|
||||||
toBlock: 'latest'
|
|
||||||
})
|
|
||||||
|
|
||||||
const leaves = events
|
|
||||||
.sort((a, b) => a.returnValues.leafIndex - b.returnValues.leafIndex) // Sort events in chronological order
|
|
||||||
.map((e) => {
|
|
||||||
const index = toBN(e.returnValues.leafIndex).toNumber()
|
|
||||||
|
|
||||||
if (toBN(e.returnValues.commitment).eq(toBN(deposit.commitmentHex))) {
|
|
||||||
leafIndex = index
|
|
||||||
}
|
|
||||||
return e.returnValues.commitment.toString(10)
|
|
||||||
})
|
|
||||||
const tree = new merkleTree(MERKLE_TREE_HEIGHT, leaves)
|
|
||||||
|
|
||||||
// Validate that our data is correct
|
|
||||||
const root = await tree.root()
|
|
||||||
const isValidRoot = await mixerContract.methods.isKnownRoot(toHex(root)).call()
|
|
||||||
const isSpent = await mixerContract.methods.isSpent(toHex(deposit.nullifierHash)).call()
|
|
||||||
assert(isValidRoot === true, 'Merkle tree is corrupted')
|
|
||||||
assert(isSpent === false, 'The note is already spent')
|
|
||||||
assert(leafIndex >= 0, 'The deposit is not found in the tree')
|
|
||||||
|
|
||||||
// Compute merkle proof of our commitment
|
|
||||||
return tree.path(leafIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate SNARK proof for withdrawal
|
|
||||||
* @param deposit Deposit object
|
|
||||||
* @param recipient Funds recipient
|
|
||||||
* @param relayer Relayer address
|
|
||||||
* @param fee Relayer fee
|
|
||||||
* @param refund Receive ether for exchanged tokens
|
|
||||||
*/
|
|
||||||
async function generateProof({ deposit, recipient, relayerAddress = 0, fee = 0, refund = 0 }) {
|
|
||||||
// Compute merkle proof of our commitment
|
|
||||||
const { root, path_elements, path_index } = await generateMerkleProof(deposit)
|
|
||||||
|
|
||||||
// Prepare circuit input
|
|
||||||
const input = {
|
|
||||||
// Public snark inputs
|
|
||||||
root: root,
|
|
||||||
nullifierHash: deposit.nullifierHash,
|
|
||||||
recipient: bigInt(recipient),
|
|
||||||
relayer: bigInt(relayerAddress),
|
|
||||||
fee: bigInt(fee),
|
|
||||||
refund: bigInt(refund),
|
|
||||||
|
|
||||||
// Private snark inputs
|
|
||||||
nullifier: deposit.nullifier,
|
|
||||||
secret: deposit.secret,
|
|
||||||
pathElements: path_elements,
|
|
||||||
pathIndices: path_index
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Generating SNARK proof')
|
|
||||||
console.time('Proof time')
|
|
||||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
|
|
||||||
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
|
||||||
console.timeEnd('Proof time')
|
|
||||||
|
|
||||||
const args = [
|
|
||||||
toHex(input.root),
|
|
||||||
toHex(input.nullifierHash),
|
|
||||||
toHex(input.recipient, 20),
|
|
||||||
toHex(input.relayer, 20),
|
|
||||||
toHex(input.fee),
|
|
||||||
toHex(input.refund)
|
|
||||||
]
|
|
||||||
|
|
||||||
return { proof, args }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do an ETH withdrawal
|
* Do an ETH withdrawal
|
||||||
* @param noteString Note to withdraw
|
* @param noteString Note to withdraw
|
||||||
* @param recipient Recipient address
|
* @param recipient Recipient address
|
||||||
*/
|
*/
|
||||||
async function withdraw({ deposit, currency, amount, recipient, relayerURL, refund = '0' }) {
|
async function withdraw({ deposit, currency, amount, recipient, relayerURL, refund = '0' }) {
|
||||||
|
// Get all deposit events from smart contract and assemble merkle tree from them
|
||||||
|
const events = await mixerContract.getPastEvents('Deposit', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: 'latest'
|
||||||
|
})
|
||||||
if (currency === 'eth' && refund !== '0') {
|
if (currency === 'eth' && refund !== '0') {
|
||||||
throw new Error('The ETH purchase is supposted to be 0 for ETH withdrawals')
|
throw new Error('The ETH purchase is supposted to be 0 for ETH withdrawals')
|
||||||
}
|
}
|
||||||
@ -237,9 +126,17 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
|||||||
recipient,
|
recipient,
|
||||||
relayerAddress: rewardAccount,
|
relayerAddress: rewardAccount,
|
||||||
fee,
|
fee,
|
||||||
refund
|
refund,
|
||||||
|
events
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Validate that our data is correct
|
||||||
|
// const isValidRoot = await mixerContract.methods.isKnownRoot(toHex(root)).call()
|
||||||
|
// const isSpent = await mixerContract.methods.isSpent(toHex(deposit.nullifierHash)).call()
|
||||||
|
// assert(isValidRoot === true, 'Merkle tree is corrupted')
|
||||||
|
// assert(isSpent === false, 'The note is already spent')
|
||||||
|
// assert(leafIndex >= 0, 'The deposit is not found in the tree')
|
||||||
|
|
||||||
console.log('Sending withdraw transaction through relay')
|
console.log('Sending withdraw transaction through relay')
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(relayerURL + '/v1/tornadoWithdraw', {
|
const response = await axios.post(relayerURL + '/v1/tornadoWithdraw', {
|
||||||
@ -261,7 +158,7 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// using private key
|
// using private key
|
||||||
const { proof, args } = await generateProof({ deposit, recipient, refund })
|
const { proof, args } = await generateProof({ deposit, recipient, refund, events })
|
||||||
|
|
||||||
console.log('Submitting withdraw transaction')
|
console.log('Submitting withdraw transaction')
|
||||||
await tornado.methods
|
await tornado.methods
|
||||||
@ -564,29 +461,13 @@ async function loadWithdrawalData({ amount, currency, deposit }) {
|
|||||||
*/
|
*/
|
||||||
async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
||||||
let contractJson, mixerJson, erc20ContractJson, erc20tornadoJson, tornadoAddress, tokenAddress
|
let contractJson, mixerJson, erc20ContractJson, erc20tornadoJson, tornadoAddress, tokenAddress
|
||||||
// TODO do we need this? should it work in browser really?
|
|
||||||
if (inBrowser) {
|
|
||||||
// Initialize using injected web3 (Metamask)
|
|
||||||
// To assemble web version run `npm run browserify`
|
|
||||||
web3 = new Web3(window.web3.currentProvider, null, {
|
|
||||||
transactionConfirmationBlocks: 1
|
|
||||||
})
|
|
||||||
contractJson = await (await fetch('build/contracts/TornadoProxy.abi.json')).json()
|
|
||||||
mixerJson = await (await fetch('build/contracts/Mixer.abi.json')).json()
|
|
||||||
circuit = await (await fetch('build/circuits/tornado.json')).json()
|
|
||||||
proving_key = await (await fetch('build/circuits/tornadoProvingKey.bin')).arrayBuffer()
|
|
||||||
MERKLE_TREE_HEIGHT = 20
|
|
||||||
ETH_AMOUNT = 1e18
|
|
||||||
TOKEN_AMOUNT = 1e19
|
|
||||||
senderAccount = (await web3.eth.getAccounts())[0]
|
|
||||||
} else {
|
|
||||||
// Initialize from local node
|
|
||||||
web3 = new Web3(rpc, null, { transactionConfirmationBlocks: 1 })
|
web3 = new Web3(rpc, null, { transactionConfirmationBlocks: 1 })
|
||||||
contractJson = require('./build/contracts/TornadoProxy.abi.json')
|
contractJson = require('./build/contracts/TornadoProxy.abi.json')
|
||||||
mixerJson = require('./build/contracts/Mixer.abi.json')
|
mixerJson = require('./build/contracts/Mixer.abi.json')
|
||||||
circuit = require('./build/circuits/tornado.json')
|
|
||||||
proving_key = fs.readFileSync('build/circuits/tornadoProvingKey.bin').buffer
|
|
||||||
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20
|
MERKLE_TREE_HEIGHT = process.env.MERKLE_TREE_HEIGHT || 20
|
||||||
|
await initialize({ merkleTreeHeight: MERKLE_TREE_HEIGHT })
|
||||||
|
|
||||||
ETH_AMOUNT = process.env.ETH_AMOUNT
|
ETH_AMOUNT = process.env.ETH_AMOUNT
|
||||||
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT
|
TOKEN_AMOUNT = process.env.TOKEN_AMOUNT
|
||||||
PRIVATE_KEY = process.env.PRIVATE_KEY
|
PRIVATE_KEY = process.env.PRIVATE_KEY
|
||||||
@ -600,9 +481,7 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
|||||||
}
|
}
|
||||||
erc20ContractJson = require('./build/contracts/ERC20Mock.json')
|
erc20ContractJson = require('./build/contracts/ERC20Mock.json')
|
||||||
erc20tornadoJson = require('./build/contracts/ERC20Tornado.json')
|
erc20tornadoJson = require('./build/contracts/ERC20Tornado.json')
|
||||||
}
|
|
||||||
// groth16 initialises a lot of Promises that will never be resolved, that's why we need to use process.exit to terminate the CLI
|
|
||||||
groth16 = await buildGroth16()
|
|
||||||
netId = await web3.eth.net.getId()
|
netId = await web3.eth.net.getId()
|
||||||
if (noteNetId && Number(noteNetId) !== netId) {
|
if (noteNetId && Number(noteNetId) !== netId) {
|
||||||
throw new Error('This note is for a different network. Specify the --rpc option explicitly')
|
throw new Error('This note is for a different network. Specify the --rpc option explicitly')
|
||||||
@ -633,21 +512,6 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
if (inBrowser) {
|
|
||||||
const instance = { currency: 'eth', amount: '0.1' }
|
|
||||||
await init(instance)
|
|
||||||
window.deposit = async () => {
|
|
||||||
await deposit(instance)
|
|
||||||
}
|
|
||||||
window.withdraw = async () => {
|
|
||||||
const noteString = prompt('Enter the note to withdraw')
|
|
||||||
const recipient = (await web3.eth.getAccounts())[0]
|
|
||||||
|
|
||||||
const { currency, amount, netId, deposit } = parseNote(noteString)
|
|
||||||
await init({ noteNetId: netId, currency, amount })
|
|
||||||
await withdraw({ deposit, currency, amount, recipient })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
program
|
program
|
||||||
.option('-r, --rpc <URL>', 'The RPC, CLI should interact with', 'http://localhost:8545')
|
.option('-r, --rpc <URL>', 'The RPC, CLI should interact with', 'http://localhost:8545')
|
||||||
.option('-R, --relayer <URL>', 'Withdraw via relayer')
|
.option('-R, --relayer <URL>', 'Withdraw via relayer')
|
||||||
@ -763,6 +627,5 @@ async function main() {
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
143
core.js
Normal file
143
core.js
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const circomlib = require('circomlib')
|
||||||
|
const websnarkUtils = require('websnark/src/utils')
|
||||||
|
const MerkleTree = require('fixed-merkle-tree')
|
||||||
|
const circuit = require('./build/circuits/tornado.json')
|
||||||
|
const path = require('path')
|
||||||
|
const proving_key = fs.readFileSync(path.resolve(__dirname, './build/circuits/tornadoProvingKey.bin')).buffer
|
||||||
|
const buildGroth16 = require('websnark/src/groth16')
|
||||||
|
const snarkjs = require('snarkjs')
|
||||||
|
const { toBN } = require('web3-utils')
|
||||||
|
const bigInt = snarkjs.bigInt
|
||||||
|
let groth16, MERKLE_TREE_HEIGHT
|
||||||
|
|
||||||
|
/** Generate random number of specified byte length */
|
||||||
|
const rbigint = (nbytes) => snarkjs.bigInt.leBuff2int(crypto.randomBytes(nbytes))
|
||||||
|
|
||||||
|
/** BigNumber to hex string of specified length */
|
||||||
|
function toHex(number, length = 32) {
|
||||||
|
const str = number instanceof Buffer ? number.toString('hex') : bigInt(number).toString(16)
|
||||||
|
return '0x' + str.padStart(length * 2, '0')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compute pedersen hash */
|
||||||
|
const pedersenHash = (data) => circomlib.babyJub.unpackPoint(circomlib.pedersenHash.hash(data))[0]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create deposit object from secret and nullifier
|
||||||
|
*/
|
||||||
|
function createDeposit({ nullifier, secret } = {}) {
|
||||||
|
if (!nullifier && !secret) {
|
||||||
|
nullifier = rbigint(31)
|
||||||
|
secret = rbigint(31)
|
||||||
|
}
|
||||||
|
const deposit = { nullifier: bigInt(nullifier), secret: bigInt(secret) }
|
||||||
|
deposit.preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)])
|
||||||
|
deposit.commitment = pedersenHash(deposit.preimage)
|
||||||
|
deposit.commitmentHex = toHex(deposit.commitment)
|
||||||
|
deposit.nullifierHash = pedersenHash(deposit.nullifier.leInt2Buff(31))
|
||||||
|
deposit.nullifierHex = toHex(deposit.nullifierHash)
|
||||||
|
return deposit
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate merkle tree for a deposit.
|
||||||
|
* @param deposit Deposit object
|
||||||
|
*/
|
||||||
|
function generateMerkleProof({ deposit, events }) {
|
||||||
|
let leafIndex = -1
|
||||||
|
|
||||||
|
let argsProperty
|
||||||
|
if (events[0].returnValues) {
|
||||||
|
argsProperty = 'returnValues'
|
||||||
|
} else if (events[0].args) {
|
||||||
|
argsProperty = 'args'
|
||||||
|
} else {
|
||||||
|
throw new Error('Only implemented for web3 and ethersjs')
|
||||||
|
}
|
||||||
|
|
||||||
|
const leaves = events
|
||||||
|
.sort((a, b) => a[argsProperty].leafIndex - b[argsProperty].leafIndex) // Sort events in chronological order
|
||||||
|
.map((e) => {
|
||||||
|
const index = toBN(e[argsProperty].leafIndex).toNumber()
|
||||||
|
|
||||||
|
if (toBN(e[argsProperty].commitment).eq(toBN(deposit.commitmentHex))) {
|
||||||
|
leafIndex = index
|
||||||
|
}
|
||||||
|
return e[argsProperty].commitment.toString(10)
|
||||||
|
})
|
||||||
|
|
||||||
|
const tree = new MerkleTree(MERKLE_TREE_HEIGHT, leaves)
|
||||||
|
|
||||||
|
// Compute merkle proof of our commitment
|
||||||
|
const { pathIndices, pathElements } = tree.path(leafIndex)
|
||||||
|
return {
|
||||||
|
pathElements,
|
||||||
|
pathIndices,
|
||||||
|
root: tree.root()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate SNARK proof for withdrawal
|
||||||
|
* @param deposit Deposit object
|
||||||
|
* @param recipient Funds recipient
|
||||||
|
* @param relayer Relayer address
|
||||||
|
* @param fee Relayer fee
|
||||||
|
* @param refund Receive ether for exchanged tokens
|
||||||
|
*/
|
||||||
|
async function generateProof({ deposit, recipient, events, relayerAddress = 0, fee = 0, refund = 0 }) {
|
||||||
|
// Compute merkle proof of our commitment
|
||||||
|
const { root, pathElements, pathIndices } = generateMerkleProof({ deposit, events })
|
||||||
|
|
||||||
|
// Prepare circuit input
|
||||||
|
const input = {
|
||||||
|
// Public snark inputs
|
||||||
|
root: root,
|
||||||
|
nullifierHash: deposit.nullifierHash,
|
||||||
|
recipient: bigInt(recipient),
|
||||||
|
relayer: bigInt(relayerAddress),
|
||||||
|
fee: bigInt(fee),
|
||||||
|
refund: bigInt(refund),
|
||||||
|
|
||||||
|
// Private snark inputs
|
||||||
|
nullifier: deposit.nullifier,
|
||||||
|
secret: deposit.secret,
|
||||||
|
pathElements,
|
||||||
|
pathIndices
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Generating SNARK proof')
|
||||||
|
console.time('Proof time')
|
||||||
|
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
|
||||||
|
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
||||||
|
console.timeEnd('Proof time')
|
||||||
|
|
||||||
|
const args = [
|
||||||
|
toHex(input.root),
|
||||||
|
toHex(input.nullifierHash),
|
||||||
|
toHex(input.recipient, 20),
|
||||||
|
toHex(input.relayer, 20),
|
||||||
|
toHex(input.fee),
|
||||||
|
toHex(input.refund)
|
||||||
|
]
|
||||||
|
|
||||||
|
return { proof, args }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initialize({ merkleTreeHeight }) {
|
||||||
|
MERKLE_TREE_HEIGHT = merkleTreeHeight
|
||||||
|
groth16 = await buildGroth16()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
initialize,
|
||||||
|
createDeposit,
|
||||||
|
generateProof,
|
||||||
|
generateMerkleProof,
|
||||||
|
rbigint,
|
||||||
|
bigInt,
|
||||||
|
toHex,
|
||||||
|
pedersenHash
|
||||||
|
}
|
13
package.json
13
package.json
@ -1,8 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "cli-tornado",
|
"name": "tornado-cli",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "core.js",
|
||||||
|
"files": [
|
||||||
|
"config.js",
|
||||||
|
"core.js",
|
||||||
|
"build",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
@ -17,7 +23,8 @@
|
|||||||
"gas-price-oracle": "^0.2.2",
|
"gas-price-oracle": "^0.2.2",
|
||||||
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
|
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
|
||||||
"web3": "^1.2.8",
|
"web3": "^1.2.8",
|
||||||
"websnark": "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d"
|
"websnark": "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d",
|
||||||
|
"fixed-merkle-tree": "^0.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^7.0.0"
|
"eslint": "^7.0.0"
|
||||||
|
18
yarn.lock
18
yarn.lock
@ -758,6 +758,16 @@ circom@0.0.35:
|
|||||||
typedarray-to-buffer "^3.1.5"
|
typedarray-to-buffer "^3.1.5"
|
||||||
web3 "^1.2.11"
|
web3 "^1.2.11"
|
||||||
|
|
||||||
|
"circomlib@git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c":
|
||||||
|
version "0.0.20"
|
||||||
|
resolved "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c"
|
||||||
|
dependencies:
|
||||||
|
blake-hash "^1.1.0"
|
||||||
|
blake2b "^2.1.3"
|
||||||
|
snarkjs "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
|
||||||
|
typedarray-to-buffer "^3.1.5"
|
||||||
|
web3 "^1.2.11"
|
||||||
|
|
||||||
class-is@^1.1.0:
|
class-is@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825"
|
resolved "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825"
|
||||||
@ -1638,6 +1648,14 @@ find-up@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
locate-path "^3.0.0"
|
locate-path "^3.0.0"
|
||||||
|
|
||||||
|
fixed-merkle-tree@^0.5.0:
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fixed-merkle-tree/-/fixed-merkle-tree-0.5.0.tgz#401cdcf3d670c1e18bc7d3a8e81322eb1b27c1d1"
|
||||||
|
integrity sha512-egOy12EzVATX3Ru2/SLtnWprVpy/sbPCt/MbeG3ANB28jykWLEYj7EjinFnOxtsgR3gTHU6xYXX53yMn/bZqyw==
|
||||||
|
dependencies:
|
||||||
|
circomlib "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c"
|
||||||
|
snarkjs "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
|
||||||
|
|
||||||
flat-cache@^2.0.1:
|
flat-cache@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
|
resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
|
||||||
|
Loading…
Reference in New Issue
Block a user