This commit is contained in:
Alexey 2020-11-04 22:23:14 +03:00
parent d22837d2bf
commit cab8a2b8db
9 changed files with 390 additions and 33 deletions

319
abis/Aggregator.abi.json Normal file
View File

@ -0,0 +1,319 @@
[
{
"inputs": [
{
"internalType": "bytes32[]",
"name": "domains",
"type": "bytes32[]"
}
],
"name": "bulkResolve",
"outputs": [
{
"internalType": "address[]",
"name": "result",
"type": "address[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
}
],
"name": "getAllProposals",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "uint256",
"name": "startTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "endTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "forVotes",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "againstVotes",
"type": "uint256"
},
{
"internalType": "bool",
"name": "executed",
"type": "bool"
},
{
"internalType": "bool",
"name": "extended",
"type": "bool"
},
{
"internalType": "enum Governance.ProposalState",
"name": "state",
"type": "uint8"
}
],
"internalType": "struct GovernanceAggregator.Proposal[]",
"name": "proposals",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
},
{
"internalType": "address[]",
"name": "accs",
"type": "address[]"
}
],
"name": "getGovernanceBalances",
"outputs": [
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "fromTokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
}
],
"name": "getPricesInETH",
"outputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "getUserData",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "latestProposalId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "latestProposalIdState",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "timelock",
"type": "uint256"
},
{
"internalType": "address",
"name": "delegatee",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Miner",
"name": "miner",
"type": "address"
},
{
"internalType": "address[]",
"name": "instances",
"type": "address[]"
}
],
"name": "minerRates",
"outputs": [
{
"internalType": "uint256[]",
"name": "_rates",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "node",
"type": "bytes32"
}
],
"name": "resolve",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
}
],
"name": "swapState",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "poolWeight",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Miner",
"name": "miner",
"type": "address"
},
{
"internalType": "address[]",
"name": "instances",
"type": "address[]"
},
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
}
],
"name": "miningData",
"outputs": [
{
"internalType": "uint256[]",
"name": "_rates",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "poolWeight",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "fromTokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
},
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
}
],
"name": "marketData",
"outputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@ -13,7 +13,7 @@ services:
environment:
REDIS_URL: redis://redis/0
nginx_proxy_read_timeout: 600
depends_on: [ redis ]
depends_on: [redis]
treeWatcher:
image: tornadocash/relayer
@ -22,7 +22,7 @@ services:
env_file: .env
environment:
REDIS_URL: redis://redis/0
depends_on: [ redis ]
depends_on: [redis]
priceWatcher:
image: tornadocash/relayer
@ -31,7 +31,7 @@ services:
env_file: .env
environment:
REDIS_URL: redis://redis/0
depends_on: [ redis ]
depends_on: [redis]
worker1:
image: tornadocash/relayer
@ -40,16 +40,16 @@ services:
env_file: .env
environment:
REDIS_URL: redis://redis/0
depends_on: [ redis ]
depends_on: [redis]
# worker2:
# image: tornadocash/relayer
# restart: always
# command: worker
# env_file: .env
# environment:
# PRIVATE_KEY: qwe
# REDIS_URL: redis://redis/0
# worker2:
# image: tornadocash/relayer
# restart: always
# command: worker
# env_file: .env
# environment:
# PRIVATE_KEY: qwe
# REDIS_URL: redis://redis/0
redis:
image: redis

View File

@ -11,7 +11,7 @@ services:
LETSENCRYPT_HOST: example.duckdns.org
REDIS_URL: redis://redis/0
nginx_proxy_read_timeout: 600
depends_on: [ redis ]
depends_on: [redis]
treeWatcher:
image: tornadocash/relayer
@ -20,7 +20,7 @@ services:
env_file: .env
environment:
REDIS_URL: redis://redis/0
depends_on: [ redis ]
depends_on: [redis]
priceWatcher:
image: tornadocash/relayer
@ -29,7 +29,7 @@ services:
env_file: .env
environment:
REDIS_URL: redis://redis/0
depends_on: [ redis ]
depends_on: [redis]
worker1:
image: tornadocash/relayer
@ -38,7 +38,7 @@ services:
env_file: .env
environment:
REDIS_URL: redis://redis/0
depends_on: [ redis ]
depends_on: [redis]
# worker2:
# image: tornadocash/relayer

View File

@ -21,14 +21,15 @@
"bull": "^3.12.1",
"circomlib": "git+ssh://git@github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c",
"dotenv": "^8.2.0",
"eth-ens-namehash": "^2.0.8",
"express": "^4.17.1",
"fixed-merkle-tree": "^0.4.0",
"gas-price-oracle": "^0.2.2",
"ioredis": "^4.14.1",
"node-fetch": "^2.6.0",
"torn-token": "git+ssh://git@github.com/tornadocash/torn-token.git#e119ff634fbe1b33b9643074bc2f6b08741c635f",
"tornado-cash-anonymity-mining": "git+ssh://git@github.com/tornadocash/tornado-anonymity-mining.git#02ff4c9061eef94617b3c1b91a02c0d25bb1c410",
"tx-manager": "git+ssh://git@github.com/tornadocash/tx-manager.git#df118be318b007e597e157504d105dfa3e6322a1",
"torn-token": "git+ssh://git@github.com/tornadocash/torn-token.git#b90fc5adccbf9a87c3bdac6175a0e038a9ed3dd8",
"uuid": "^8.3.0",
"web3": "^1.3.0",
"web3-core-promievent": "^1.3.0",

View File

@ -1,6 +1,7 @@
require('dotenv').config()
const jobType = require('./jobTypes')
const tornConfig = require('torn-token')
module.exports = {
netId: Number(process.env.NET_ID) || 42,
@ -9,12 +10,11 @@ module.exports = {
wsRpcUrl: process.env.WS_RPC_URL,
oracleRpcUrl: process.env.ORACLE_RPC_URL || 'https://mainnet.infura.io/',
oracleAddress: '0xA2b8E7ee7c8a18ea561A5CF7C9C365592026E374',
minerAddress: '0x3E0a9C6Cf76136862De28ce25a56cDBF38EF9D37', // each network has its own instance
tornadoProxyAddress: '0x98529F6FaE5AdaFfa0AaDA37d9017AF9a4281E13', // each network has its own instance
swapAddress: '0x1E73e0a484a595B692f3d212642AE4B3BF30E7e3',
aggregatorAddress: '0x748F37B04eAB454Ad8cF4F5d6814984448c79B35',
minerMerkleTreeHeight: 20,
privateKey: process.env.PRIVATE_KEY,
instances: require('torn-token').instances,
instances: tornConfig.instances,
torn: tornConfig,
port: process.env.APP_PORT || 8000,
tornadoServiceFee: Number(process.env.REGULAR_TORNADO_WITHDRAW_FEE),
miningServiceFee: Number(process.env.MINING_SERVICE_FEE),

30
src/resolver.js Normal file
View File

@ -0,0 +1,30 @@
const { httpRpcUrl, aggregatorAddress } = require('./config')
const Web3 = require('web3')
const web3 = new Web3(httpRpcUrl)
const aggregator = new web3.eth.Contract(require('../abis/Aggregator.abi.json'), aggregatorAddress)
const ens = require('eth-ens-namehash')
class ENSResolver {
constructor() {
this.addresses = {}
}
async resolve(domains) {
if (!Array.isArray(domains)) {
domains = [domains]
}
const unresolved = domains.filter(d => !this.addresses[d])
if (unresolved.length) {
const resolved = await aggregator.methods.bulkResolve(unresolved.map(ens.hash)).call()
for (let i = 0; i < resolved.length; i++) {
this.addresses[domains[i]] = resolved[i]
}
}
const addresses = domains.map(domain => this.addresses[domain])
return addresses.length === 1 ? addresses[0] : addresses
}
}
module.exports = ENSResolver

View File

@ -1,12 +1,15 @@
const MerkleTree = require('fixed-merkle-tree')
const { redisUrl, wsRpcUrl, minerMerkleTreeHeight, minerAddress } = require('./config')
const { redisUrl, wsRpcUrl, minerMerkleTreeHeight, torn } = require('./config')
const { poseidonHash2 } = require('./utils')
const { toBN } = require('web3-utils')
const Redis = require('ioredis')
const redis = new Redis(redisUrl)
const ENSResolver = require('./resolver')
const resolver = new ENSResolver()
const Web3 = require('web3')
const web3 = new Web3(wsRpcUrl)
const contract = new web3.eth.Contract(require('../abis/mining.abi.json'), minerAddress)
const MinerABI = require('../abis/mining.abi.json')
let contract
let tree, eventSubscription, blockSubscription
@ -86,6 +89,7 @@ async function rebuild() {
async function init() {
console.log('Initializing')
contract = new web3.eth.Contract(MinerABI, await resolver.resolve(torn.miningV2.address))
const block = await web3.eth.getBlockNumber()
const events = await fetchEvents(0, block)
tree = new MerkleTree(minerMerkleTreeHeight, events, { hashFunction: poseidonHash2 })

View File

@ -14,17 +14,17 @@ const { poseidonHash2, getInstance, fromDecimals } = require('./utils')
const jobType = require('./jobTypes')
const {
netId,
torn,
httpRpcUrl,
redisUrl,
privateKey,
swapAddress,
minerAddress,
tornadoProxyAddress,
gasLimits,
instances,
tornadoServiceFee,
miningServiceFee,
} = require('./config')
const ENSResolver = require('./resolver')
const resolver = new ENSResolver()
const { TxManager } = require('tx-manager')
const { Controller } = require('tornado-cash-anonymity-mining')
@ -63,6 +63,7 @@ async function fetchTree() {
const update = await controller.treeUpdate(args.account.outputCommitment, tree)
const minerAddress = await resolver.resolve(torn.miningV2.address)
const instance = new web3.eth.Contract(miningABI, minerAddress)
const data =
currentJob.data.type === 'MINING_REWARD'
@ -79,7 +80,7 @@ async function fetchTree() {
async function start() {
web3 = new Web3(httpRpcUrl)
txManager = new TxManager({ privateKey, rpcUrl: httpRpcUrl, config: { CONFIRMATIONS: 6 } })
swap = new web3.eth.Contract(swapABI, swapAddress)
swap = new web3.eth.Contract(swapABI, resolver.resolve(torn.rewardSwap.address))
redisSubscribe.subscribe('treeUpdate', fetchTree)
await fetchTree()
const provingKeys = {
@ -168,16 +169,18 @@ async function checkMiningFee({ args }) {
}
}
function getTxObject({ data }) {
async function getTxObject({ data }) {
if (data.type === jobType.TORNADO_WITHDRAW) {
const tornadoProxyAddress = await resolver.resolve(torn.tornadoProxy.address)
const contract = new web3.eth.Contract(tornadoProxyABI, tornadoProxyAddress)
const calldata = contract.methods.withdraw(data.contract, data.proof, ...data.args).encodeABI()
return {
value: data.args[5],
to: tornadoProxyAddress,
data: calldata
data: calldata,
}
} else {
const minerAddress = await resolver.resolve(torn.miningV2.address)
const contract = new web3.eth.Contract(miningABI, minerAddress)
const method = data.type === jobType.MINING_REWARD ? 'reward' : 'withdraw'
const calldata = contract.methods[method](data.proof, data.args).encodeABI()
@ -197,7 +200,7 @@ async function process(job) {
await updateStatus(status.ACCEPTED)
console.log(`Start processing a new ${job.data.type} job #${job.id}`)
await checkFee(job)
currentTx = await txManager.createTx(getTxObject(job))
currentTx = await txManager.createTx(await getTxObject(job))
if (job.data.type !== jobType.TORNADO_WITHDRAW) {
await fetchTree()

View File

@ -1466,7 +1466,7 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eth-ens-namehash@2.0.8:
eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf"
integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88=
@ -3928,9 +3928,9 @@ toidentifier@1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
"torn-token@git+ssh://git@github.com/tornadocash/torn-token.git#b90fc5adccbf9a87c3bdac6175a0e038a9ed3dd8":
"torn-token@git+ssh://git@github.com/tornadocash/torn-token.git#e119ff634fbe1b33b9643074bc2f6b08741c635f":
version "1.0.0"
resolved "git+ssh://git@github.com/tornadocash/torn-token.git#b90fc5adccbf9a87c3bdac6175a0e038a9ed3dd8"
resolved "git+ssh://git@github.com/tornadocash/torn-token.git#e119ff634fbe1b33b9643074bc2f6b08741c635f"
dependencies:
"@openzeppelin/contracts" "^3.1.0"
dotenv "^8.2.0"