diff --git a/abis/swap.abi.json b/abis/swap.abi.json new file mode 100644 index 0000000..91b2a68 --- /dev/null +++ b/abis/swap.abi.json @@ -0,0 +1,241 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_torn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_miningCap", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_initialLiquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newWeight", + "type": "uint256" + } + ], + "name": "PoolWeightUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "pTORN", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "TORN", + "type": "uint256" + } + ], + "name": "Swap", + "type": "event" + }, + { + "inputs": [], + "name": "DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "miner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "startTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokensSold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "torn", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_miner", + "type": "address" + } + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "swap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "getExpectedReturn", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tornVirtualBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newWeight", + "type": "uint256" + } + ], + "name": "setPoolWeight", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/config.js b/config.js index d158e8b..abe01cb 100644 --- a/config.js +++ b/config.js @@ -12,6 +12,7 @@ let config = { oracleRpcUrl: process.env.ORACLE_RPC_URL || 'https://mainnet.infura.io/', oracleAddress: '0xA2b8E7ee7c8a18ea561A5CF7C9C365592026E374', minerAddress: '0x0834DeaFD83130AE1867173919f693070DaE6eeD', + swapAddress: '0x0834DeaFD83130AE1867173919f693070DaE6eeD', minerMerkleTreeHeight: 10, privateKey: process.env.PRIVATE_KEY, instances: { diff --git a/package.json b/package.json index 4630b75..540d52c 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,14 @@ "gas-price-oracle": "^0.1.5", "ioredis": "^4.14.1", "node-fetch": "^2.6.0", - "tornado-cash-anonymity-mining": "git+https://github.com/tornadocash/tornado-anonymity-mining.git#820bd83254f3264cebaf255869641ebc33288dc3", + "tornado-cash-anonymity-mining": "git+https://github.com/tornadocash/tornado-anonymity-mining.git#e3ae8b98b14eb7fee7cb8c93221920a20b1e0cd8", "uuid": "^8.3.0", "web3": "^1.3.0", "web3-core-promievent": "^1.3.0", "web3-utils": "^1.2.2", - "why-is-node-running": "^2.2.0" + "why-is-node-running": "^2.2.0", + "snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", + "websnark": "git+https://github.com/tornadocash/websnark.git#86a526718cd6f6f5d31bdb1fe26a9ec8819f633e" }, "devDependencies": { "chai": "^4.2.0", diff --git a/src/queue.js b/src/queue.js index ce2273a..63cced4 100644 --- a/src/queue.js +++ b/src/queue.js @@ -28,6 +28,7 @@ async function getJob(uuid) { async function getJobStatus(uuid) { const job = await getJob(uuid) + // todo job.data doesn't contain current status and other stuff? return job.data } diff --git a/src/worker.js b/src/worker.js index b23c71d..2369b39 100644 --- a/src/worker.js +++ b/src/worker.js @@ -1,3 +1,4 @@ +const fs = require('fs') const Web3 = require('web3') const { numberToHex, toBN } = require('web3-utils') const MerkleTree = require('fixed-merkle-tree') @@ -6,27 +7,46 @@ const { GasPriceOracle } = require('gas-price-oracle') const tornadoABI = require('../abis/tornadoABI.json') const miningABI = require('../abis/mining.abi.json') +const swapABI = require('../abis/swap.abi.json') const { queue } = require('./queue') const { poseidonHash2 } = require('./utils') -const { rpcUrl, redisUrl, privateKey, updateConfig, rewardAccount, minerAddress } = require('../config') +const { rpcUrl, redisUrl, privateKey, updateConfig, swapAddress, rewardAccount, minerAddress } = require('../config') const TxManager = require('./TxManager') +const { Controller } = require('tornado-cash-anonymity-mining') let web3 let currentTx let currentJob let tree let txManager +let controller const redis = new Redis(redisUrl) const redisSubscribe = new Redis(redisUrl) const gasPriceOracle = new GasPriceOracle({ defaultRpc: rpcUrl }) async function fetchTree() { + console.log('got tree update') const elements = await redis.get('tree:elements') const convert = (_, val) => (typeof val === 'string' ? toBN(val) : val) tree = MerkleTree.deserialize(JSON.parse(elements, convert), poseidonHash2) - if (currentTx) { - // todo replace + if (currentTx && currentJob && ['miningReward', 'miningWithdraw'].includes(currentJob.data.type)) { + const { proof, args } = currentJob.data.data + if (args.account.inputRoot === tree.root()) { // todo check type + return + } + + const update = await controller.treeUpdate(args.account.outputCommitment, tree) + + const instance = new web3.eth.Contract(tornadoABI, minerAddress) + const data = currentJob.data.type === 'miningReward' ? + instance.methods.reward(proof, args, update.proof, update.args).encodeABI() : + instance.methods.withdraw(proof, args, update.proof, update.args).encodeABI() + currentTx = await currentTx.replace({ + to: minerAddress, + data, + }) + console.log('replaced pending tx') } } @@ -34,9 +54,15 @@ async function start() { web3 = new Web3(rpcUrl) txManager = new TxManager({ privateKey, rpcUrl }) updateConfig({ rewardAccount: txManager.address }) - queue.process(process) redisSubscribe.subscribe('treeUpdate', fetchTree) await fetchTree() + const provingKeys = { + treeUpdateCircuit: require('../keys/TreeUpdate.json'), + treeUpdateProvingKey: fs.readFileSync('./keys/TreeUpdate_proving_key.bin').buffer, + } + controller = new Controller({ provingKeys }) + await controller.init() + queue.process(process) console.log('Worker started') } @@ -45,6 +71,13 @@ async function checkTornadoFee(/* contract, fee, refund*/) { console.log('fast', fast) } +async function checkMiningFee(points) { + const swap = new web3.eth.Contract(swapABI, swapAddress) + const TornAmount = await swap.getExpectedReturn(points).call() + + // todo: use desired torn/eth rate and compute the same way as in tornado +} + async function process(job) { switch (job.data.type) { case 'tornadoWithdraw': diff --git a/yarn.lock b/yarn.lock index 3df6c7e..ba4fd35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3862,9 +3862,9 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== -"tornado-cash-anonymity-mining@git+https://github.com/tornadocash/tornado-anonymity-mining.git#820bd83254f3264cebaf255869641ebc33288dc3": +"tornado-cash-anonymity-mining@git+https://github.com/tornadocash/tornado-anonymity-mining.git#e3ae8b98b14eb7fee7cb8c93221920a20b1e0cd8": version "1.0.0" - resolved "git+https://github.com/tornadocash/tornado-anonymity-mining.git#820bd83254f3264cebaf255869641ebc33288dc3" + resolved "git+https://github.com/tornadocash/tornado-anonymity-mining.git#e3ae8b98b14eb7fee7cb8c93221920a20b1e0cd8" dependencies: circomlib "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c" eth-sig-util "^2.5.3"