tornado-relayer/src/validator.js

200 lines
5.0 KiB
JavaScript
Raw Normal View History

const { isAddress, toChecksumAddress } = require('web3-utils')
2020-09-27 22:28:34 -04:00
const { getInstance } = require('./utils')
2020-09-28 10:54:54 -04:00
const Ajv = require('ajv')
const ajv = new Ajv({ format: 'fast' })
2020-09-27 22:28:34 -04:00
2020-09-28 10:54:54 -04:00
ajv.addKeyword('isAddress', {
validate: (schema, data) => {
try {
return isAddress(data)
} catch (e) {
return false
2020-09-27 22:28:34 -04:00
}
2020-09-28 10:54:54 -04:00
},
errors: true,
2020-09-28 10:54:54 -04:00
})
ajv.addKeyword('isKnownContract', {
validate: (schema, data) => {
try {
return getInstance(data) !== null
} catch (e) {
return false
2020-09-27 22:28:34 -04:00
}
2020-09-28 10:54:54 -04:00
},
errors: true,
2020-09-28 10:54:54 -04:00
})
2020-09-28 23:17:42 -04:00
ajv.addKeyword('isFeeRecipient', {
2020-09-28 10:54:54 -04:00
validate: (schema, data) => {
try {
return require('../config').rewardAccount === toChecksumAddress(data)
2020-09-28 10:54:54 -04:00
} catch (e) {
return false
}
},
errors: true,
2020-09-28 10:54:54 -04:00
})
const addressType = { type: 'string', pattern: '^0x[a-fA-F0-9]{40}$', isAddress: true }
const proofType = { type: 'string', pattern: '^0x[a-fA-F0-9]{512}$' }
const encryptedAccountType = { type: 'string', pattern: '^0x[a-fA-F0-9]{392}$' }
const bytes32Type = { type: 'string', pattern: '^0x[a-fA-F0-9]{64}$' }
2020-09-28 23:17:42 -04:00
const instanceType = { ...addressType, isKnownContract: true }
const relayerType = { ...addressType, isFeeRecipient: true }
2020-09-28 10:54:54 -04:00
const tornadoWithdrawSchema = {
type: 'object',
properties: {
proof: proofType,
contract: instanceType,
args: {
type: 'array',
maxItems: 6,
minItems: 6,
items: [bytes32Type, bytes32Type, addressType, relayerType, bytes32Type, bytes32Type],
},
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: ['proof', 'contract', 'args'],
2020-09-27 22:28:34 -04:00
}
2020-09-28 10:54:54 -04:00
const miningRewardSchema = {
type: 'object',
properties: {
proof: proofType,
args: {
type: 'object',
properties: {
rate: bytes32Type,
fee: bytes32Type,
instance: instanceType,
rewardNullifier: bytes32Type,
extDataHash: bytes32Type,
depositRoot: bytes32Type,
withdrawalRoot: bytes32Type,
extData: {
type: 'object',
properties: {
relayer: relayerType,
encryptedAccount: encryptedAccountType,
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: ['relayer', 'encryptedAccount'],
2020-09-28 10:54:54 -04:00
},
account: {
type: 'object',
properties: {
inputRoot: bytes32Type,
inputNullifierHash: bytes32Type,
outputRoot: bytes32Type,
outputPathIndices: bytes32Type,
outputCommitment: bytes32Type,
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: [
'inputRoot',
'inputNullifierHash',
'outputRoot',
'outputPathIndices',
'outputCommitment',
],
},
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: [
'rate',
'fee',
'instance',
'rewardNullifier',
'extDataHash',
'depositRoot',
'withdrawalRoot',
'extData',
'account',
],
},
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: ['proof', 'args'],
2020-09-28 10:54:54 -04:00
}
2020-09-27 22:28:34 -04:00
2020-09-28 10:54:54 -04:00
const miningWithdrawSchema = {
type: 'object',
properties: {
proof: proofType,
args: {
type: 'object',
properties: {
amount: bytes32Type,
fee: bytes32Type,
extDataHash: bytes32Type,
extData: {
type: 'object',
properties: {
recipient: addressType,
relayer: relayerType,
encryptedAccount: encryptedAccountType,
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: ['relayer', 'encryptedAccount', 'recipient'],
2020-09-28 10:54:54 -04:00
},
account: {
type: 'object',
properties: {
inputRoot: bytes32Type,
inputNullifierHash: bytes32Type,
outputRoot: bytes32Type,
outputPathIndices: bytes32Type,
outputCommitment: bytes32Type,
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: [
'inputRoot',
'inputNullifierHash',
'outputRoot',
'outputPathIndices',
'outputCommitment',
],
},
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: ['amount', 'fee', 'extDataHash', 'extData', 'account'],
},
2020-09-28 10:54:54 -04:00
},
additionalProperties: false,
required: ['proof', 'args'],
2020-09-27 22:28:34 -04:00
}
2020-09-28 10:54:54 -04:00
const validateTornadoWithdraw = ajv.compile(tornadoWithdrawSchema)
const validateMiningReward = ajv.compile(miningRewardSchema)
const validateMiningWithdraw = ajv.compile(miningWithdrawSchema)
2020-09-27 22:28:34 -04:00
2020-09-28 10:54:54 -04:00
function getInputError(validator, data) {
validator(data)
if (validator.errors) {
const error = validator.errors[0]
return `${error.dataPath} ${error.message}`
}
2020-09-27 22:28:34 -04:00
return null
}
2020-09-28 10:54:54 -04:00
function getTornadoWithdrawInputError(data) {
return getInputError(validateTornadoWithdraw, data)
2020-09-27 22:28:34 -04:00
}
2020-09-28 10:54:54 -04:00
function getMiningRewardInputError(data) {
return getInputError(validateMiningReward, data)
2020-09-27 22:28:34 -04:00
}
2020-09-28 10:54:54 -04:00
function getMiningWithdrawInputError(data) {
return getInputError(validateMiningWithdraw, data)
2020-09-27 22:28:34 -04:00
}
module.exports = {
2020-09-28 10:54:54 -04:00
getTornadoWithdrawInputError,
getMiningRewardInputError,
getMiningWithdrawInputError,
2020-09-27 22:28:34 -04:00
}