Merge remote-tracking branch 'upstream/release-8.0' into chore/merge-8.0-into-8.1
This commit is contained in:
commit
ec32a6f0cd
19 changed files with 102 additions and 31 deletions
|
|
@ -52,8 +52,8 @@ const BINARIES = {
|
|||
files: [['bitcoind', 'bitcoincashd'], ['bitcoin-cli', 'bitcoincash-cli']]
|
||||
},
|
||||
XMR: {
|
||||
url: 'https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.0.0.tar.bz2',
|
||||
dir: 'monero-x86_64-linux-gnu-v0.18.0.0',
|
||||
url: 'https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.1.0.tar.bz2',
|
||||
dir: 'monero-x86_64-linux-gnu-v0.18.1.0',
|
||||
files: [['monerod', 'monerod'], ['monero-wallet-rpc', 'monero-wallet-rpc']]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,19 +139,33 @@ function getBlockchainSyncStatus (cryptoList) {
|
|||
})
|
||||
}
|
||||
|
||||
function isInstalled (crypto) {
|
||||
return isInstalledSoftware(crypto) && isInstalledVolume(crypto)
|
||||
}
|
||||
|
||||
function isDisabled (crypto) {
|
||||
switch (crypto.cryptoCode) {
|
||||
case 'ETH':
|
||||
return 'Use admin\'s Infura plugin'
|
||||
case 'ZEC':
|
||||
return isInstalled(crypto) && 'Installed' || isInstalled(_.find(it => it.code === 'monero', cryptos)) && 'Insufficient resources. Contact support.'
|
||||
case 'XMR':
|
||||
return isInstalled(crypto) && 'Installed' || isInstalled(_.find(it => it.code === 'zcash', cryptos)) && 'Insufficient resources. Contact support.'
|
||||
default:
|
||||
return isInstalled(crypto) && 'Installed'
|
||||
}
|
||||
}
|
||||
|
||||
function run () {
|
||||
const choices = _.flow([
|
||||
_.filter(c => c.type !== 'erc-20'),
|
||||
_.map(c => {
|
||||
const checked = isInstalledSoftware(c) && isInstalledVolume(c)
|
||||
const name = c.code === 'ethereum' ? 'Ethereum and/or USDT' : c.display
|
||||
return {
|
||||
name,
|
||||
value: c.code,
|
||||
checked,
|
||||
disabled: c.cryptoCode === 'ETH'
|
||||
? 'Use admin\'s Infura plugin'
|
||||
: checked && 'Installed'
|
||||
checked: isInstalled(c),
|
||||
disabled: isDisabled(c)
|
||||
}
|
||||
}),
|
||||
])(cryptos)
|
||||
|
|
@ -160,6 +174,15 @@ function run () {
|
|||
|
||||
const validateAnswers = async (answers) => {
|
||||
if (_.size(answers) > 2) return { message: `Please insert a maximum of two coins to install.`, isValid: false }
|
||||
|
||||
if (
|
||||
_.isEmpty(_.difference(['monero', 'zcash'], answers)) ||
|
||||
(_.includes('monero', answers) && isInstalled(_.find(it => it.code === 'zcash', cryptos))) ||
|
||||
(_.includes('zcash', answers) && isInstalled(_.find(it => it.code === 'monero', cryptos)))
|
||||
) {
|
||||
return { message: `Zcash and Monero installations are temporarily mutually exclusive, given the space needed for their blockchains. Contact support for more information.`, isValid: false }
|
||||
}
|
||||
|
||||
return getBlockchainSyncStatus(cryptos)
|
||||
.then(blockchainStatuses => {
|
||||
const result = _.reduce((acc, value) => ({ ...acc, [value]: _.isNil(acc[value]) ? 1 : acc[value] + 1 }), {}, _.values(blockchainStatuses))
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ function transaction () {
|
|||
SELECT 'address' AS type, to_address AS value FROM cash_in_txs UNION
|
||||
SELECT 'address' AS type, to_address AS value FROM cash_out_txs UNION
|
||||
SELECT 'status' AS type, ${cashInTx.TRANSACTION_STATES} AS value FROM cash_in_txs UNION
|
||||
SELECT 'status' AS type, ${CASH_OUT_TRANSACTION_STATES} AS value FROM cash_out_txs
|
||||
SELECT 'status' AS type, ${CASH_OUT_TRANSACTION_STATES} AS value FROM cash_out_txs UNION
|
||||
SELECT 'sweep status' AS type, CASE WHEN swept THEN 'Swept' WHEN NOT swept THEN 'Unswept' END AS value FROM cash_out_txs
|
||||
) f`
|
||||
|
||||
return db.any(sql)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ const typeDef = gql`
|
|||
batchError: String
|
||||
walletScore: Int
|
||||
profit: String
|
||||
swept: Boolean
|
||||
}
|
||||
|
||||
type Filter {
|
||||
|
|
@ -58,8 +59,8 @@ const typeDef = gql`
|
|||
}
|
||||
|
||||
type Query {
|
||||
transactions(from: Date, until: Date, limit: Int, offset: Int, deviceId: ID, txClass: String, machineName: String, customerName: String, fiatCode: String, cryptoCode: String, toAddress: String, status: String, excludeTestingCustomers: Boolean): [Transaction] @auth
|
||||
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int, txClass: String, machineName: String, customerName: String, fiatCode: String, cryptoCode: String, toAddress: String, status: String, timezone: String, excludeTestingCustomers: Boolean, simplified: Boolean): String @auth
|
||||
transactions(from: Date, until: Date, limit: Int, offset: Int, deviceId: ID, txClass: String, machineName: String, customerName: String, fiatCode: String, cryptoCode: String, toAddress: String, status: String, swept: Boolean, excludeTestingCustomers: Boolean): [Transaction] @auth
|
||||
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int, txClass: String, machineName: String, customerName: String, fiatCode: String, cryptoCode: String, toAddress: String, status: String, swept: Boolean, timezone: String, excludeTestingCustomers: Boolean, simplified: Boolean): String @auth
|
||||
transactionCsv(id: ID, txClass: String, timezone: String): String @auth
|
||||
txAssociatedDataCsv(id: ID, txClass: String, timezone: String): String @auth
|
||||
transactionFilters: [Filter] @auth
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ function batch (
|
|||
cryptoCode = null,
|
||||
toAddress = null,
|
||||
status = null,
|
||||
swept = null,
|
||||
excludeTestingCustomers = false,
|
||||
simplified
|
||||
) {
|
||||
|
|
@ -109,14 +110,33 @@ function batch (
|
|||
AND ($11 is null or txs.crypto_code = $11)
|
||||
AND ($12 is null or txs.to_address = $12)
|
||||
AND ($13 is null or txs.txStatus = $13)
|
||||
AND ($14 is null or txs.swept = $14)
|
||||
${excludeTestingCustomers ? `AND c.is_test_customer is false` : ``}
|
||||
AND (fiat > 0)
|
||||
ORDER BY created DESC limit $4 offset $5`
|
||||
|
||||
return Promise.all([
|
||||
// The swept filter is cash-out only, so omit the cash-in query entirely
|
||||
const hasCashInOnlyFilters = false
|
||||
const hasCashOutOnlyFilters = !_.isNil(swept)
|
||||
|
||||
let promises
|
||||
|
||||
if (hasCashInOnlyFilters && hasCashOutOnlyFilters) {
|
||||
throw new Error('Trying to filter transactions with mutually exclusive filters')
|
||||
}
|
||||
|
||||
if (hasCashInOnlyFilters) {
|
||||
promises = [db.any(cashInSql, [cashInTx.PENDING_INTERVAL, from, until, limit, offset, id, txClass, machineName, customerName, fiatCode, cryptoCode, toAddress, status])]
|
||||
} else if (hasCashOutOnlyFilters) {
|
||||
promises = [db.any(cashOutSql, [REDEEMABLE_AGE, from, until, limit, offset, id, txClass, machineName, customerName, fiatCode, cryptoCode, toAddress, status, swept])]
|
||||
} else {
|
||||
promises = [
|
||||
db.any(cashInSql, [cashInTx.PENDING_INTERVAL, from, until, limit, offset, id, txClass, machineName, customerName, fiatCode, cryptoCode, toAddress, status]),
|
||||
db.any(cashOutSql, [REDEEMABLE_AGE, from, until, limit, offset, id, txClass, machineName, customerName, fiatCode, cryptoCode, toAddress, status])
|
||||
])
|
||||
db.any(cashOutSql, [REDEEMABLE_AGE, from, until, limit, offset, id, txClass, machineName, customerName, fiatCode, cryptoCode, toAddress, status, swept])
|
||||
]
|
||||
}
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(packager)
|
||||
.then(res => {
|
||||
if (simplified) return simplifiedBatch(res)
|
||||
|
|
|
|||
|
|
@ -808,7 +808,7 @@ function plugins (settings, deviceId) {
|
|||
|
||||
function sweepHd () {
|
||||
const sql = `SELECT id, crypto_code, hd_index FROM cash_out_txs
|
||||
WHERE hd_index IS NOT NULL AND NOT swept AND status IN ('confirmed', 'instant') AND created < now() - interval '1 week'`
|
||||
WHERE hd_index IS NOT NULL AND NOT swept AND status IN ('confirmed', 'instant') AND created > now() - interval '1 week'`
|
||||
|
||||
return db.any(sql)
|
||||
.then(rows => Promise.all(rows.map(sweepHdRow)))
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const Tx = require('ethereumjs-tx')
|
|||
const { default: PQueue } = require('p-queue')
|
||||
const util = require('ethereumjs-util')
|
||||
const coins = require('@lamassu/coins')
|
||||
const { default: PQueue } = require('p-queue')
|
||||
|
||||
const _pify = require('pify')
|
||||
const BN = require('../../../bn')
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { P, Label3 } from 'src/components/typography'
|
|||
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
||||
import { ReactComponent as FilterIcon } from 'src/styling/icons/button/filter/white.svg'
|
||||
import { ReactComponent as ReverseFilterIcon } from 'src/styling/icons/button/filter/zodiac.svg'
|
||||
import { onlyFirstToUpper } from 'src/utils/string'
|
||||
import { onlyFirstToUpper, singularOrPlural } from 'src/utils/string'
|
||||
|
||||
import { chipStyles, styles } from './SearchFilter.styles'
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ const SearchFilter = ({
|
|||
filters,
|
||||
onFilterDelete,
|
||||
deleteAllFilters,
|
||||
entries
|
||||
entries = 0
|
||||
}) => {
|
||||
const chipClasses = useChipStyles()
|
||||
const classes = useStyles()
|
||||
|
|
@ -40,8 +40,11 @@ const SearchFilter = ({
|
|||
</div>
|
||||
<div className={classes.deleteWrapper}>
|
||||
{
|
||||
<Label3 className={classes.entries}>{`${entries ??
|
||||
0} entries`}</Label3>
|
||||
<Label3 className={classes.entries}>{`${entries} ${singularOrPlural(
|
||||
entries,
|
||||
`entry`,
|
||||
`entries`
|
||||
)}`}</Label3>
|
||||
}
|
||||
<ActionButton
|
||||
color="secondary"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import {
|
|||
offErrorColor
|
||||
} from 'src/styling/variables'
|
||||
import { URI } from 'src/utils/apollo'
|
||||
import { SWEEPABLE_CRYPTOS } from 'src/utils/constants'
|
||||
import * as Customer from 'src/utils/customer'
|
||||
|
||||
import CopyToClipboard from './CopyToClipboard'
|
||||
|
|
@ -389,6 +390,14 @@ const DetailsRow = ({ it: tx, timezone }) => {
|
|||
</ActionButton>
|
||||
)}
|
||||
</div>
|
||||
{!R.isNil(tx.swept) && R.includes(tx.cryptoCode, SWEEPABLE_CRYPTOS) && (
|
||||
<div className={classes.swept}>
|
||||
<Label>Sweep status</Label>
|
||||
<span className={classes.bold}>
|
||||
{tx.swept ? `Swept` : `Unswept`}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Label>Other actions</Label>
|
||||
<div className={classes.otherActionsGroup}>
|
||||
|
|
|
|||
|
|
@ -131,5 +131,8 @@ export default {
|
|||
},
|
||||
error: {
|
||||
color: tomato
|
||||
},
|
||||
swept: {
|
||||
width: 250
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ const GET_TRANSACTIONS = gql`
|
|||
$cryptoCode: String
|
||||
$toAddress: String
|
||||
$status: String
|
||||
$swept: Boolean
|
||||
) {
|
||||
transactions(
|
||||
limit: $limit
|
||||
|
|
@ -87,6 +88,7 @@ const GET_TRANSACTIONS = gql`
|
|||
cryptoCode: $cryptoCode
|
||||
toAddress: $toAddress
|
||||
status: $status
|
||||
swept: $swept
|
||||
) {
|
||||
id
|
||||
txClass
|
||||
|
|
@ -122,6 +124,7 @@ const GET_TRANSACTIONS = gql`
|
|||
batchError
|
||||
walletScore
|
||||
profit
|
||||
swept
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -247,7 +250,8 @@ const Transactions = () => {
|
|||
fiatCode: filtersObject.fiat,
|
||||
cryptoCode: filtersObject.crypto,
|
||||
toAddress: filtersObject.address,
|
||||
status: filtersObject.status
|
||||
status: filtersObject.status,
|
||||
swept: filtersObject.swept === 'Swept'
|
||||
})
|
||||
|
||||
refetch && refetch()
|
||||
|
|
@ -270,7 +274,8 @@ const Transactions = () => {
|
|||
fiatCode: filtersObject.fiat,
|
||||
cryptoCode: filtersObject.crypto,
|
||||
toAddress: filtersObject.address,
|
||||
status: filtersObject.status
|
||||
status: filtersObject.status,
|
||||
swept: filtersObject.swept === 'Swept'
|
||||
})
|
||||
|
||||
refetch && refetch()
|
||||
|
|
@ -288,7 +293,8 @@ const Transactions = () => {
|
|||
fiatCode: filtersObject.fiat,
|
||||
cryptoCode: filtersObject.crypto,
|
||||
toAddress: filtersObject.address,
|
||||
status: filtersObject.status
|
||||
status: filtersObject.status,
|
||||
swept: filtersObject.swept === 'Swept'
|
||||
})
|
||||
|
||||
refetch && refetch()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const MANUAL = 'manual'
|
|||
|
||||
const IP_CHECK_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
||||
|
||||
const SWEEPABLE_CRYPTOS = ['ETH']
|
||||
|
||||
export {
|
||||
CURRENCY_MAX,
|
||||
MIN_NUMBER_OF_CASSETTES,
|
||||
|
|
@ -15,5 +17,6 @@ export {
|
|||
AUTOMATIC,
|
||||
MANUAL,
|
||||
WALLET_SCORING_DEFAULT_THRESHOLD,
|
||||
IP_CHECK_REGEX
|
||||
IP_CHECK_REGEX,
|
||||
SWEEPABLE_CRYPTOS
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,8 @@
|
|||
"lamassu-operator": "./bin/lamassu-operator",
|
||||
"lamassu-coinatmradar": "./bin/lamassu-coinatmradar",
|
||||
"lamassu-eth-recovery": "./bin/lamassu-eth-recovery",
|
||||
"lamassu-update-cassettes": "./bin/lamassu-update-cassettes"
|
||||
"lamassu-update-cassettes": "./bin/lamassu-update-cassettes",
|
||||
"lamassu-clean-parsed-id": "./bin/lamassu-clean-parsed-id"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node bin/lamassu-server",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.fa6ae8da.chunk.js",
|
||||
"main.js.map": "/static/js/main.fa6ae8da.chunk.js.map",
|
||||
"main.js": "/static/js/main.659fb869.chunk.js",
|
||||
"main.js.map": "/static/js/main.659fb869.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.5b925903.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.5b925903.js.map",
|
||||
"static/js/2.0102a725.chunk.js": "/static/js/2.0102a725.chunk.js",
|
||||
|
|
@ -154,6 +154,6 @@
|
|||
"entrypoints": [
|
||||
"static/js/runtime-main.5b925903.js",
|
||||
"static/js/2.0102a725.chunk.js",
|
||||
"static/js/main.fa6ae8da.chunk.js"
|
||||
"static/js/main.659fb869.chunk.js"
|
||||
]
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="robots" content="noindex"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Lamassu Admin</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root" class="root"></div><script>!function(e){function r(r){for(var n,a,l=r[0],i=r[1],f=r[2],c=0,s=[];c<l.length;c++)a=l[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var i=t[l];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var l=this["webpackJsonplamassu-admin"]=this["webpackJsonplamassu-admin"]||[],i=l.push.bind(l);l.push=r,l=l.slice();for(var f=0;f<l.length;f++)r(l[f]);var p=i;t()}([])</script><script src="/static/js/2.0102a725.chunk.js"></script><script src="/static/js/main.fa6ae8da.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="robots" content="noindex"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Lamassu Admin</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root" class="root"></div><script>!function(e){function r(r){for(var n,a,l=r[0],i=r[1],f=r[2],c=0,s=[];c<l.length;c++)a=l[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var i=t[l];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var l=this["webpackJsonplamassu-admin"]=this["webpackJsonplamassu-admin"]||[],i=l.push.bind(l);l.push=r,l=l.slice();for(var f=0;f<l.length;f++)r(l[f]);var p=i;t()}([])</script><script src="/static/js/2.0102a725.chunk.js"></script><script src="/static/js/main.659fb869.chunk.js"></script></body></html>
|
||||
2
public/static/js/main.659fb869.chunk.js
Normal file
2
public/static/js/main.659fb869.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
public/static/js/main.659fb869.chunk.js.map
Normal file
1
public/static/js/main.659fb869.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue