const axios = require('axios') const _ = require('lodash/fp') const logger = require('../../../logger') const NAME = 'CipherTrace' const SUPPORTED_COINS = ['BTC', 'ETH', 'BCH', 'LTC', 'BNB', 'RSK'] function getClient (account) { if (_.isNil(account) || !account.enabled) return null const [ctv1, username, secretKey] = account.authorizationValue.split(':') if (_.isNil(ctv1) || _.isNil(username) || _.isNil(secretKey)) { throw new Error('Invalid CipherTrace configuration') } const apiVersion = ctv1.slice(-2) const authHeader = { 'Authorization': account.authorizationValue } return { apiVersion, authHeader } } function rateWallet (account, cryptoCode, address) { const client = getClient(account) if (!_.includes(_.toUpper(cryptoCode), SUPPORTED_COINS) || _.isNil(client)) return Promise.resolve(null) const { apiVersion, authHeader } = client const threshold = account.scoreThreshold logger.info(`** DEBUG ** rateWallet ENDPOINT: https://rest.ciphertrace.com/aml/${apiVersion}/${_.toLower(cryptoCode)}/risk?address=${address}`) return axios.get(`https://rest.ciphertrace.com/aml/${apiVersion}/${_.toLower(cryptoCode)}/risk?address=${address}`, { headers: authHeader }) .then(res => ({ address, score: res.data.risk, isValid: res.data.risk < threshold })) .then(result => { logger.info(`** DEBUG ** rateWallet RETURN: ${result}`) return result }) .catch(err => { logger.error(`** DEBUG ** rateWallet ERROR: ${err.message}`) throw err }) } function isValidWalletScore (account, score) { const client = getClient(account) if (_.isNil(client)) return Promise.resolve(true) const threshold = account.scoreThreshold return _.isNil(account) ? Promise.resolve(true) : Promise.resolve(score < threshold) } function getTransactionHash (account, cryptoCode, receivingAddress) { const client = getClient(account) if (!_.includes(_.toUpper(cryptoCode), SUPPORTED_COINS) || _.isNil(client)) return Promise.resolve(null) const { apiVersion, authHeader } = client logger.info(`** DEBUG ** getTransactionHash ENDPOINT: https://rest.ciphertrace.com/api/${apiVersion}/${_.toLower(cryptoCode) !== 'btc' ? `${_.toLower(cryptoCode)}_` : ``}address/search?features=tx&address=${receivingAddress}&mempool=true`) return new Promise(resolve => { setTimeout(resolve, 2000) }) .then(axios.get(`https://rest.ciphertrace.com/api/${apiVersion}/${_.toLower(cryptoCode) !== 'btc' ? `${_.toLower(cryptoCode)}_` : ``}address/search?features=tx&address=${receivingAddress}&mempool=true`, { headers: authHeader })) .then(res => { const data = res.data if (_.size(data.txHistory) > 1) { logger.warn('An address generated by this wallet was used in more than one transaction') } logger.info(`** DEBUG ** getTransactionHash RETURN: ${_.join(', ', _.map(it => it.txHash, data.txHistory))}`) return _.join(', ', _.map(it => it.txHash, data.txHistory)) }) .catch(err => { logger.error(`** DEBUG ** getTransactionHash ERROR: ${err}`) throw err }) } function getInputAddresses (account, cryptoCode, txHashes) { const client = getClient(account) if (!_.includes(_.toUpper(cryptoCode), SUPPORTED_COINS) || _.isNil(client)) return Promise.resolve(null) const { apiVersion, authHeader } = client logger.info(`** DEBUG ** getInputAddresses ENDPOINT: https://rest.ciphertrace.com/api/${apiVersion}/${_.toLower(cryptoCode) !== 'btc' ? `${_.toLower(cryptoCode)}_` : ``}tx?txhashes=${txHashes}`) return axios.get(`https://rest.ciphertrace.com/api/${apiVersion}/${_.toLower(cryptoCode) !== 'btc' ? `${_.toLower(cryptoCode)}_` : ``}tx?txhashes=${txHashes}`, { headers: authHeader }) .then(res => { const data = res.data if (_.size(data.transactions) > 1) { logger.warn('An address generated by this wallet was used in more than one transaction') } const transactionInputs = _.flatMap(it => it.inputs, data.transactions) const inputAddresses = _.map(it => it.address, transactionInputs) logger.info(`** DEBUG ** getInputAddresses RETURN: ${inputAddresses}`) return inputAddresses }) .catch(err => { logger.error(`** DEBUG ** getInputAddresses ERROR: ${err.message}`) throw err }) } module.exports = { NAME, rateWallet, isValidWalletScore, getTransactionHash, getInputAddresses }