2019-09-19 17:46:20 -04:00
|
|
|
const { numberToHex, toWei, toHex, toBN, toChecksumAddress } = require('web3-utils')
|
2019-12-03 08:26:16 -05:00
|
|
|
const mixerABI = require('../abis/mixerABI.json')
|
2019-11-23 03:18:54 -05:00
|
|
|
const {
|
|
|
|
isValidProof, isValidArgs, isKnownContract, isEnoughFee
|
|
|
|
} = require('./utils')
|
2019-12-03 08:26:16 -05:00
|
|
|
const config = require('../config')
|
2019-07-18 10:45:33 -04:00
|
|
|
|
2019-11-23 03:18:54 -05:00
|
|
|
const { web3, fetcher } = require('./instances')
|
2019-07-24 13:19:00 -04:00
|
|
|
|
2019-11-23 03:18:54 -05:00
|
|
|
async function relay (req, resp) {
|
2019-11-14 08:24:01 -05:00
|
|
|
const { proof, args, contract } = req.body
|
2019-11-23 03:18:54 -05:00
|
|
|
const gasPrices = fetcher.gasPrices
|
2019-11-14 08:24:01 -05:00
|
|
|
let { valid , reason } = isValidProof(proof)
|
2019-07-18 08:43:26 -04:00
|
|
|
if (!valid) {
|
|
|
|
console.log('Proof is invalid:', reason)
|
2019-11-07 20:25:43 -05:00
|
|
|
return resp.status(400).json({ error: 'Proof format is invalid' })
|
2019-07-18 08:43:26 -04:00
|
|
|
}
|
2019-09-19 17:46:20 -04:00
|
|
|
|
2019-11-14 08:24:01 -05:00
|
|
|
({ valid , reason } = isValidArgs(args))
|
2019-09-19 17:46:20 -04:00
|
|
|
if (!valid) {
|
2019-11-14 08:24:01 -05:00
|
|
|
console.log('Args are invalid:', reason)
|
|
|
|
return resp.status(400).json({ error: 'Withdraw arguments are invalid' })
|
2019-09-19 17:46:20 -04:00
|
|
|
}
|
2019-07-18 08:43:26 -04:00
|
|
|
|
2019-11-26 10:01:37 -05:00
|
|
|
let currency, amount
|
|
|
|
( { valid, currency, amount } = isKnownContract(contract))
|
2019-11-14 08:24:01 -05:00
|
|
|
if (!valid) {
|
|
|
|
console.log('Contract does not exist:', contract)
|
|
|
|
return resp.status(400).json({ error: 'This relayer does not support the token' })
|
2019-11-07 20:25:43 -05:00
|
|
|
}
|
|
|
|
|
2019-11-14 08:24:01 -05:00
|
|
|
const [ root, nullifierHash, recipient, relayer, fee, refund ] = [
|
|
|
|
args[0],
|
|
|
|
args[1],
|
|
|
|
toChecksumAddress(args[2]),
|
|
|
|
toChecksumAddress(args[3]),
|
|
|
|
toBN(args[4]),
|
|
|
|
toBN(args[5])
|
|
|
|
]
|
2019-11-23 04:20:08 -05:00
|
|
|
console.log('fee, refund', fee.toString(), refund.toString())
|
2019-11-15 04:01:59 -05:00
|
|
|
if (currency === 'eth' && !refund.isZero()) {
|
|
|
|
return resp.status(400).json({ error: 'Cannot send refund for eth currency.' })
|
|
|
|
}
|
|
|
|
|
2019-11-14 08:24:01 -05:00
|
|
|
if (relayer !== web3.eth.defaultAccount) {
|
|
|
|
console.log('This proof is for different relayer:', relayer)
|
2019-09-19 17:46:20 -04:00
|
|
|
return resp.status(400).json({ error: 'Relayer address is invalid' })
|
|
|
|
}
|
2019-07-18 08:43:26 -04:00
|
|
|
|
|
|
|
try {
|
2019-09-19 15:56:45 -04:00
|
|
|
const mixer = new web3.eth.Contract(mixerABI, req.body.contract)
|
2019-11-14 08:24:01 -05:00
|
|
|
const isSpent = await mixer.methods.isSpent(nullifierHash).call()
|
2019-07-18 08:43:26 -04:00
|
|
|
if (isSpent) {
|
2019-07-23 12:07:33 -04:00
|
|
|
return resp.status(400).json({ error: 'The note has been spent.' })
|
2019-07-18 08:43:26 -04:00
|
|
|
}
|
2019-11-14 08:24:01 -05:00
|
|
|
const isKnownRoot = await mixer.methods.isKnownRoot(root).call()
|
2019-07-18 09:30:24 -04:00
|
|
|
if (!isKnownRoot) {
|
2019-07-23 12:07:33 -04:00
|
|
|
return resp.status(400).json({ error: 'The merkle root is too old or invalid.' })
|
2019-07-18 09:30:24 -04:00
|
|
|
}
|
2019-11-15 04:01:59 -05:00
|
|
|
|
2019-12-03 08:26:16 -05:00
|
|
|
let gas = await mixer.methods.withdraw(proof, ...args).estimateGas({
|
2019-11-14 08:24:01 -05:00
|
|
|
from: web3.eth.defaultAccount,
|
|
|
|
value: refund
|
|
|
|
})
|
2019-11-15 04:01:59 -05:00
|
|
|
|
|
|
|
gas += 50000
|
2019-11-23 03:18:54 -05:00
|
|
|
const ethPrices = fetcher.ethPrices
|
2019-11-26 10:01:37 -05:00
|
|
|
const { isEnough, reason } = isEnoughFee({ gas, gasPrices, currency, amount, refund, ethPrices, fee })
|
2019-11-15 04:01:59 -05:00
|
|
|
if (!isEnough) {
|
|
|
|
console.log(`Wrong fee: ${reason}`)
|
|
|
|
return resp.status(400).json({ error: reason })
|
|
|
|
}
|
|
|
|
|
2019-12-03 08:26:16 -05:00
|
|
|
const data = mixer.methods.withdraw(proof, ...args).encodeABI()
|
|
|
|
const tx = {
|
2019-11-09 20:03:46 -05:00
|
|
|
from: web3.eth.defaultAccount,
|
2019-12-03 08:26:16 -05:00
|
|
|
value: numberToHex(refund),
|
2019-11-15 04:01:59 -05:00
|
|
|
gas: numberToHex(gas),
|
2019-07-18 08:43:26 -04:00
|
|
|
gasPrice: toHex(toWei(gasPrices.fast.toString(), 'gwei')),
|
2019-12-03 08:26:16 -05:00
|
|
|
to: mixer._address,
|
|
|
|
netId: config.netId,
|
|
|
|
data,
|
|
|
|
nonce: config.nonce
|
|
|
|
}
|
|
|
|
config.nonce++
|
|
|
|
let signedTx = await web3.eth.accounts.signTransaction(tx, config.privateKey)
|
|
|
|
let result = web3.eth.sendSignedTransaction(signedTx.rawTransaction)
|
|
|
|
|
2019-11-14 08:24:01 -05:00
|
|
|
result.once('transactionHash', function(txHash){
|
|
|
|
resp.json({ txHash })
|
2019-12-03 08:26:16 -05:00
|
|
|
console.log(`A new successfully sent tx ${txHash} for the ${recipient}`)
|
2019-07-18 08:43:26 -04:00
|
|
|
}).on('error', function(e){
|
2019-12-03 08:26:16 -05:00
|
|
|
config.nonce--
|
2019-12-03 08:46:18 -05:00
|
|
|
console.error('on transactionHash error', e.message)
|
2019-07-23 12:07:33 -04:00
|
|
|
return resp.status(400).json({ error: 'Proof is malformed.' })
|
2019-07-18 08:43:26 -04:00
|
|
|
})
|
|
|
|
} catch (e) {
|
2019-12-03 08:26:16 -05:00
|
|
|
console.error(e, 'estimate gas failed')
|
2019-07-23 12:07:33 -04:00
|
|
|
return resp.status(400).json({ error: 'Proof is malformed or spent.' })
|
2019-07-18 08:43:26 -04:00
|
|
|
}
|
|
|
|
}
|
2019-11-14 08:24:01 -05:00
|
|
|
|
2019-11-23 03:18:54 -05:00
|
|
|
module.exports = relay
|