diff --git a/.env.example b/.env.example index 5616157..633c888 100644 --- a/.env.example +++ b/.env.example @@ -3,5 +3,7 @@ RPC_URL=https://kovan.infura.io/v3/a3f4d001c1fc4a359ea70dd27fd9cb51 PRIVATE_KEY= ETH_MIXER_ADDRESS=0x1Cea940cA15a303A0E01B7F8589F39fF34308DB2 DAI_MIXER_ADDRESS=0x7ed3fC8042e18db889A0466F49c438bB1410b3c7 +# 25 means 2.5% +RELAYER_FEE=25 APP_PORT=8000 \ No newline at end of file diff --git a/config.js b/config.js index 1813700..f64012d 100644 --- a/config.js +++ b/config.js @@ -1,20 +1,23 @@ require('dotenv').config() module.exports = { - netId: process.env.NET_ID || 42, + netId: Number(process.env.NET_ID) || 42, rpcUrl: process.env.RPC_URL || 'https://kovan.infura.io/v3/a3f4d001c1fc4a359ea70dd27fd9cb51', privateKey: process.env.PRIVATE_KEY, mixers: [ { address: process.env.ETH_MIXER_ADDRESS, - currency: 'eth' + currency: 'eth', + amount: '0.1' }, { address: process.env.DAI_MIXER_ADDRESS, - currency: 'dai' + currency: 'dai', + amount: '100' } ], defaultGasPrice: 2, gasOracleUrls: ['https://www.etherchain.org/api/gasPriceOracle', 'https://gasprice.poa.network/'], port: process.env.APP_PORT, //dai - tokens: ['0x6b175474e89094c44da98b954eedeac495271d0f'] + tokens: ['0x6b175474e89094c44da98b954eedeac495271d0f'], + relayerServiceFee: process.env.RELAYER_FEE } \ No newline at end of file diff --git a/src/index.js b/src/index.js index a316e07..f830478 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ const express = require('express') -const { netId, mixers, port } = require('../config') +const { netId, mixers, port, relayerServiceFee } = require('../config') const relayController = require('./relayController') const { fetcher, web3 } = require('./instances') @@ -28,7 +28,7 @@ app.get('/', function (req, res) { app.get('/status', function (req, res) { const { ethPrices, gasPrices } = fetcher - res.json({ relayerAddress: web3.eth.defaultAccount, mixers, gasPrices, netId, ethPrices }) + res.json({ relayerAddress: web3.eth.defaultAccount, mixers, gasPrices, netId, ethPrices, relayerServiceFee }) }) app.post('/relay', relayController) @@ -43,4 +43,5 @@ console.log(`relayerAddress: ${web3.eth.defaultAccount}`) console.log(`mixers: ${JSON.stringify(mixers)}`) console.log(`gasPrices: ${JSON.stringify(fetcher.gasPrices)}`) console.log(`netId: ${netId}`) -console.log(`ethPrices: ${JSON.stringify(fetcher.ethPrices)}`) \ No newline at end of file +console.log(`ethPrices: ${JSON.stringify(fetcher.ethPrices)}`) +console.log(`Service fee: ${relayerServiceFee / 10}%`) \ No newline at end of file diff --git a/src/relayController.js b/src/relayController.js index 72e9458..9b35e4a 100644 --- a/src/relayController.js +++ b/src/relayController.js @@ -21,8 +21,8 @@ async function relay (req, resp) { return resp.status(400).json({ error: 'Withdraw arguments are invalid' }) } - let currency - ( { valid, currency } = isKnownContract(contract)) + let currency, amount + ( { valid, currency, amount } = isKnownContract(contract)) if (!valid) { console.log('Contract does not exist:', contract) return resp.status(400).json({ error: 'This relayer does not support the token' }) @@ -73,7 +73,7 @@ async function relay (req, resp) { gas += 50000 const ethPrices = fetcher.ethPrices - const { isEnough, reason } = isEnoughFee({ gas, gasPrices, currency, refund, ethPrices, fee }) + const { isEnough, reason } = isEnoughFee({ gas, gasPrices, currency, amount, refund, ethPrices, fee }) if (!isEnough) { console.log(`Wrong fee: ${reason}`) return resp.status(400).json({ error: reason }) diff --git a/src/utils.js b/src/utils.js index bd9b176..a54e9ad 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,5 @@ const { isHexStrict, toBN, toWei } = require('web3-utils') -const { mixers } = require('../config') +const { mixers, relayerServiceFee } = require('../config') function isValidProof(proof) { // validator expects `websnarkUtils.toSolidityInput(proof)` output @@ -46,7 +46,7 @@ function isValidArgs(args) { function isKnownContract(contract) { for (let i = 0; i < mixers.length; i++) { if (mixers[i].address === contract) { - return { valid: true, currency: mixers[i].currency } + return { valid: true, currency: mixers[i].currency, amount: mixers[i].amount } } } return { valid: false } @@ -56,12 +56,14 @@ function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } -function isEnoughFee({ gas, gasPrices, currency, refund, ethPrices, fee }) { +function isEnoughFee({ gas, gasPrices, currency, amount, refund, ethPrices, fee }) { + // TODO tokens can have less then 18 decimals + const feePercent = toBN(toWei(amount)).mul(toBN(relayerServiceFee)).div(toBN('1000')) const expense = toBN(toWei(gasPrices.fast.toString(), 'gwei')).mul(toBN(gas)) let desiredFee switch (currency) { case 'eth': { - desiredFee = expense + desiredFee = expense.add(feePercent) break } case 'dai': { @@ -69,10 +71,11 @@ function isEnoughFee({ gas, gasPrices, currency, refund, ethPrices, fee }) { expense.add(refund) .mul(toBN(10 ** 18)) .div(toBN(ethPrices.dai)) + desiredFee = desiredFee.add(feePercent) break } } - console.log('desired fee', desiredFee.toString()) + console.log('desired fee, feePercent', desiredFee.toString(), feePercent.toString()) if (fee.lt(desiredFee)) { return { isEnough: false, reason: 'Not enough fee' } }