feat: turn address into a coin-agnostic solution
This commit is contained in:
parent
c5f3caab2f
commit
473bb15c24
9 changed files with 122 additions and 177 deletions
|
|
@ -5,38 +5,37 @@ const notifierQueries = require('./notifier/queries')
|
||||||
const getBlacklist = () => {
|
const getBlacklist = () => {
|
||||||
return db.any(`SELECT * FROM blacklist`).then(res =>
|
return db.any(`SELECT * FROM blacklist`).then(res =>
|
||||||
res.map(item => ({
|
res.map(item => ({
|
||||||
cryptoCode: item.crypto_code,
|
|
||||||
address: item.address
|
address: item.address
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete row from blacklist table by crypto code and address
|
// Delete row from blacklist table by crypto code and address
|
||||||
const deleteFromBlacklist = (cryptoCode, address) => {
|
const deleteFromBlacklist = address => {
|
||||||
const sql = `DELETE FROM blacklist WHERE crypto_code = $1 AND address = $2`
|
const sql = `DELETE FROM blacklist WHERE address = $1`
|
||||||
notifierQueries.clearBlacklistNotification(cryptoCode, address)
|
notifierQueries.clearBlacklistNotification(address)
|
||||||
return db.none(sql, [cryptoCode, address])
|
return db.none(sql, [address])
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertIntoBlacklist = (cryptoCode, address) => {
|
const insertIntoBlacklist = address => {
|
||||||
return db
|
return db
|
||||||
.none(
|
.none(
|
||||||
'INSERT INTO blacklist (crypto_code, address) VALUES ($1, $2);',
|
'INSERT INTO blacklist (address) VALUES ($1);',
|
||||||
[cryptoCode, address]
|
[address]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function blocked (address, cryptoCode) {
|
function blocked (address) {
|
||||||
const sql = `SELECT * FROM blacklist WHERE address = $1 AND crypto_code = $2`
|
const sql = `SELECT * FROM blacklist WHERE address = $1`
|
||||||
return db.any(sql, [address, cryptoCode])
|
return db.any(sql, [address])
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToUsedAddresses (address, cryptoCode) {
|
function addToUsedAddresses (address) {
|
||||||
// ETH reuses addresses
|
// ETH reuses addresses
|
||||||
if (cryptoCode === 'ETH') return Promise.resolve()
|
// if (cryptoCode === 'ETH') return Promise.resolve()
|
||||||
|
|
||||||
const sql = `INSERT INTO blacklist (crypto_code, address) VALUES ($1, $2)`
|
const sql = `INSERT INTO blacklist (address) VALUES ($1)`
|
||||||
return db.oneOrNone(sql, [cryptoCode, address])
|
return db.oneOrNone(sql, [address])
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ function logActionById (action, _rec, txId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForBlacklisted (tx) {
|
function checkForBlacklisted (tx) {
|
||||||
return blacklist.blocked(tx.toAddress, tx.cryptoCode)
|
return blacklist.blocked(tx.toAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
function postProcess (r, pi, isBlacklisted, addressReuse, walletScore) {
|
function postProcess (r, pi, isBlacklisted, addressReuse, walletScore) {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ const resolvers = {
|
||||||
blacklist: () => blacklist.getBlacklist()
|
blacklist: () => blacklist.getBlacklist()
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
deleteBlacklistRow: (...[, { cryptoCode, address }]) =>
|
deleteBlacklistRow: (...[, { address }]) =>
|
||||||
blacklist.deleteFromBlacklist(cryptoCode, address),
|
blacklist.deleteFromBlacklist(address),
|
||||||
insertBlacklistRow: (...[, { cryptoCode, address }]) =>
|
insertBlacklistRow: (...[, { address }]) =>
|
||||||
blacklist.insertIntoBlacklist(cryptoCode, address)
|
blacklist.insertIntoBlacklist(address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ const { gql } = require('apollo-server-express')
|
||||||
|
|
||||||
const typeDef = gql`
|
const typeDef = gql`
|
||||||
type Blacklist {
|
type Blacklist {
|
||||||
cryptoCode: String!
|
|
||||||
address: String!
|
address: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -11,8 +10,8 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
deleteBlacklistRow(cryptoCode: String!, address: String!): Blacklist @auth
|
deleteBlacklistRow(address: String!): Blacklist @auth
|
||||||
insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist @auth
|
insertBlacklistRow(address: String!): Blacklist @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
18
migrations/1664907000312-coin-agnostic-blacklist.js
Normal file
18
migrations/1664907000312-coin-agnostic-blacklist.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
var db = require('./db')
|
||||||
|
|
||||||
|
exports.up = function (next) {
|
||||||
|
var sql = [
|
||||||
|
`CREATE TABLE blacklist_temp (
|
||||||
|
address TEXT NOT NULL UNIQUE
|
||||||
|
)`
|
||||||
|
`INSERT INTO blacklist_temp (address) SELECT DISTINCT address FROM blacklist`,
|
||||||
|
`DROP TABLE blacklist`,
|
||||||
|
`ALTER TABLE blacklist_temp RENAME TO blacklist`
|
||||||
|
]
|
||||||
|
|
||||||
|
db.multi(sql, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = function (next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useQuery, useMutation } from '@apollo/react-hooks'
|
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||||
import { utils as coinUtils } from '@lamassu/coins'
|
import { addressDetector } from '@lamassu/coins'
|
||||||
import { Box, Dialog, DialogContent, DialogActions } from '@material-ui/core'
|
import { Box, Dialog, DialogContent, DialogActions } from '@material-ui/core'
|
||||||
import Grid from '@material-ui/core/Grid'
|
import Grid from '@material-ui/core/Grid'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
|
@ -8,16 +8,10 @@ import * as R from 'ramda'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import { HelpTooltip } from 'src/components/Tooltip'
|
import { HelpTooltip } from 'src/components/Tooltip'
|
||||||
import {
|
import { Link, Button, IconButton } from 'src/components/buttons'
|
||||||
Link,
|
|
||||||
Button,
|
|
||||||
IconButton,
|
|
||||||
SupportLinkButton
|
|
||||||
} from 'src/components/buttons'
|
|
||||||
import { Switch } from 'src/components/inputs'
|
import { Switch } from 'src/components/inputs'
|
||||||
import Sidebar from 'src/components/layout/Sidebar'
|
|
||||||
import TitleSection from 'src/components/layout/TitleSection'
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
import { H4, H2, Label2, P, Info3, Info2 } from 'src/components/typography'
|
import { H2, Label2, P, Info3, Info2 } from 'src/components/typography'
|
||||||
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
||||||
import { fromNamespace, toNamespace } from 'src/utils/config'
|
import { fromNamespace, toNamespace } from 'src/utils/config'
|
||||||
|
|
||||||
|
|
@ -27,12 +21,9 @@ import BlacklistTable from './BlacklistTable'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const groupByCode = R.groupBy(obj => obj.cryptoCode)
|
|
||||||
|
|
||||||
const DELETE_ROW = gql`
|
const DELETE_ROW = gql`
|
||||||
mutation DeleteBlacklistRow($cryptoCode: String!, $address: String!) {
|
mutation DeleteBlacklistRow($address: String!) {
|
||||||
deleteBlacklistRow(cryptoCode: $cryptoCode, address: $address) {
|
deleteBlacklistRow(address: $address) {
|
||||||
cryptoCode
|
|
||||||
address
|
address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +32,6 @@ const DELETE_ROW = gql`
|
||||||
const GET_BLACKLIST = gql`
|
const GET_BLACKLIST = gql`
|
||||||
query getBlacklistData {
|
query getBlacklistData {
|
||||||
blacklist {
|
blacklist {
|
||||||
cryptoCode
|
|
||||||
address
|
address
|
||||||
}
|
}
|
||||||
cryptoCurrencies {
|
cryptoCurrencies {
|
||||||
|
|
@ -64,9 +54,8 @@ const GET_INFO = gql`
|
||||||
`
|
`
|
||||||
|
|
||||||
const ADD_ROW = gql`
|
const ADD_ROW = gql`
|
||||||
mutation InsertBlacklistRow($cryptoCode: String!, $address: String!) {
|
mutation InsertBlacklistRow($address: String!) {
|
||||||
insertBlacklistRow(cryptoCode: $cryptoCode, address: $address) {
|
insertBlacklistRow(address: $address) {
|
||||||
cryptoCode
|
|
||||||
address
|
address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,10 +107,6 @@ const Blacklist = () => {
|
||||||
const { data: blacklistResponse } = useQuery(GET_BLACKLIST)
|
const { data: blacklistResponse } = useQuery(GET_BLACKLIST)
|
||||||
const { data: configData } = useQuery(GET_INFO)
|
const { data: configData } = useQuery(GET_INFO)
|
||||||
const [showModal, setShowModal] = useState(false)
|
const [showModal, setShowModal] = useState(false)
|
||||||
const [clickedItem, setClickedItem] = useState({
|
|
||||||
code: 'BTC',
|
|
||||||
display: 'Bitcoin'
|
|
||||||
})
|
|
||||||
const [errorMsg, setErrorMsg] = useState(null)
|
const [errorMsg, setErrorMsg] = useState(null)
|
||||||
const [deleteDialog, setDeleteDialog] = useState(false)
|
const [deleteDialog, setDeleteDialog] = useState(false)
|
||||||
const [confirmDialog, setConfirmDialog] = useState(false)
|
const [confirmDialog, setConfirmDialog] = useState(false)
|
||||||
|
|
@ -147,11 +132,6 @@ const Blacklist = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
const blacklistData = R.path(['blacklist'])(blacklistResponse) ?? []
|
const blacklistData = R.path(['blacklist'])(blacklistResponse) ?? []
|
||||||
const availableCurrencies = R.filter(
|
|
||||||
coin => coinUtils.getEquivalentCode(coin.code) === coin.code
|
|
||||||
)(R.path(['cryptoCurrencies'], blacklistResponse) ?? [])
|
|
||||||
|
|
||||||
const formattedData = groupByCode(blacklistData)
|
|
||||||
|
|
||||||
const complianceConfig =
|
const complianceConfig =
|
||||||
configData?.config && fromNamespace('compliance')(configData.config)
|
configData?.config && fromNamespace('compliance')(configData.config)
|
||||||
|
|
@ -165,12 +145,8 @@ const Blacklist = () => {
|
||||||
return saveConfig({ variables: { config } })
|
return saveConfig({ variables: { config } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClickSidebarItem = e => {
|
const handleDeleteEntry = address => {
|
||||||
setClickedItem({ code: e.code, display: e.display })
|
deleteEntry({ variables: { address } })
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleteEntry = (cryptoCode, address) => {
|
|
||||||
deleteEntry({ variables: { cryptoCode, address } })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleConfirmDialog = confirm => {
|
const handleConfirmDialog = confirm => {
|
||||||
|
|
@ -180,21 +156,21 @@ const Blacklist = () => {
|
||||||
setConfirmDialog(false)
|
setConfirmDialog(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAddress = (cryptoCode, address) => {
|
const validateAddress = address => {
|
||||||
try {
|
try {
|
||||||
return !R.isNil(coinUtils.parseUrl(cryptoCode, 'main', address))
|
return !R.isEmpty(addressDetector.detectAddress(address).matches)
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const addToBlacklist = async (cryptoCode, address) => {
|
const addToBlacklist = async address => {
|
||||||
setErrorMsg(null)
|
setErrorMsg(null)
|
||||||
if (!validateAddress(cryptoCode, address)) {
|
if (!validateAddress(address)) {
|
||||||
setErrorMsg('Invalid address')
|
setErrorMsg('Invalid address')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await addEntry({ variables: { cryptoCode, address } })
|
const res = await addEntry({ variables: { address } })
|
||||||
if (!res.errors) {
|
if (!res.errors) {
|
||||||
return setShowModal(false)
|
return setShowModal(false)
|
||||||
}
|
}
|
||||||
|
|
@ -218,86 +194,64 @@ const Blacklist = () => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TitleSection title="Blacklisted addresses">
|
<TitleSection title="Blacklisted addresses">
|
||||||
<Box display="flex" justifyContent="flex-end">
|
<Box display="flex" alignItems="center" justifyContent="flex-end">
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="end"
|
||||||
|
mr="15px">
|
||||||
|
<P>Enable paper wallet (only)</P>
|
||||||
|
<Switch
|
||||||
|
checked={enablePaperWalletOnly}
|
||||||
|
onChange={e =>
|
||||||
|
enablePaperWalletOnly
|
||||||
|
? addressReuseSave({
|
||||||
|
enablePaperWalletOnly: e.target.checked
|
||||||
|
})
|
||||||
|
: setConfirmDialog(true)
|
||||||
|
}
|
||||||
|
value={enablePaperWalletOnly}
|
||||||
|
/>
|
||||||
|
<Label2>{enablePaperWalletOnly ? 'On' : 'Off'}</Label2>
|
||||||
|
<HelpTooltip width={304}>
|
||||||
|
<P>
|
||||||
|
The "Enable paper wallet (only)" option means that only paper
|
||||||
|
wallets will be printed for users, and they won't be permitted
|
||||||
|
to scan an address from their own wallet.
|
||||||
|
</P>
|
||||||
|
</HelpTooltip>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="flex-end"
|
||||||
|
mr="15px">
|
||||||
|
<P>Reject reused addresses</P>
|
||||||
|
<Switch
|
||||||
|
checked={rejectAddressReuse}
|
||||||
|
onChange={event => {
|
||||||
|
addressReuseSave({ rejectAddressReuse: event.target.checked })
|
||||||
|
}}
|
||||||
|
value={rejectAddressReuse}
|
||||||
|
/>
|
||||||
|
<Label2>{rejectAddressReuse ? 'On' : 'Off'}</Label2>
|
||||||
|
<HelpTooltip width={304}>
|
||||||
|
<P>
|
||||||
|
The "Reject reused addresses" option means that all addresses
|
||||||
|
that are used once will be automatically rejected if there's an
|
||||||
|
attempt to use them again on a new transaction.
|
||||||
|
</P>
|
||||||
|
</HelpTooltip>
|
||||||
|
</Box>
|
||||||
<Link color="primary" onClick={() => setShowModal(true)}>
|
<Link color="primary" onClick={() => setShowModal(true)}>
|
||||||
Blacklist new addresses
|
Blacklist new addresses
|
||||||
</Link>
|
</Link>
|
||||||
</Box>
|
</Box>
|
||||||
</TitleSection>
|
</TitleSection>
|
||||||
<Grid container className={classes.grid}>
|
<Grid container className={classes.grid}>
|
||||||
<Sidebar
|
|
||||||
data={availableCurrencies}
|
|
||||||
isSelected={R.propEq('code', clickedItem.code)}
|
|
||||||
displayName={it => it.display}
|
|
||||||
onClick={onClickSidebarItem}
|
|
||||||
/>
|
|
||||||
<div className={classes.content}>
|
<div className={classes.content}>
|
||||||
<Box display="flex" justifyContent="space-between" mb={3}>
|
|
||||||
<H4 noMargin className={classes.subtitle}>
|
|
||||||
{clickedItem.display
|
|
||||||
? `${clickedItem.display} blacklisted addresses`
|
|
||||||
: ''}{' '}
|
|
||||||
</H4>
|
|
||||||
<Box
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="end"
|
|
||||||
mr="-140px">
|
|
||||||
<P>Enable paper wallet (only)</P>
|
|
||||||
<Switch
|
|
||||||
checked={enablePaperWalletOnly}
|
|
||||||
onChange={e =>
|
|
||||||
enablePaperWalletOnly
|
|
||||||
? addressReuseSave({
|
|
||||||
enablePaperWalletOnly: e.target.checked
|
|
||||||
})
|
|
||||||
: setConfirmDialog(true)
|
|
||||||
}
|
|
||||||
value={enablePaperWalletOnly}
|
|
||||||
/>
|
|
||||||
<Label2>{enablePaperWalletOnly ? 'On' : 'Off'}</Label2>
|
|
||||||
<HelpTooltip width={304}>
|
|
||||||
<P>
|
|
||||||
The "Enable paper wallet (only)" option means that only paper
|
|
||||||
wallets will be printed for users, and they won't be permitted
|
|
||||||
to scan an address from their own wallet.
|
|
||||||
</P>
|
|
||||||
</HelpTooltip>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="flex-end"
|
|
||||||
mr="-5px">
|
|
||||||
<P>Reject reused addresses</P>
|
|
||||||
<Switch
|
|
||||||
checked={rejectAddressReuse}
|
|
||||||
onChange={event => {
|
|
||||||
addressReuseSave({ rejectAddressReuse: event.target.checked })
|
|
||||||
}}
|
|
||||||
value={rejectAddressReuse}
|
|
||||||
/>
|
|
||||||
<Label2>{rejectAddressReuse ? 'On' : 'Off'}</Label2>
|
|
||||||
<HelpTooltip width={304}>
|
|
||||||
<P>
|
|
||||||
The "Reject reused addresses" option means that all addresses
|
|
||||||
that are used once will be automatically rejected if there's
|
|
||||||
an attempt to use them again on a new transaction.
|
|
||||||
</P>
|
|
||||||
<P>
|
|
||||||
For details please read the relevant knowledgebase article:
|
|
||||||
</P>
|
|
||||||
<SupportLinkButton
|
|
||||||
link="https://support.lamassu.is/hc/en-us/articles/360033622211-Reject-Address-Reuse"
|
|
||||||
label="Reject Address Reuse"
|
|
||||||
bottomSpace="1"
|
|
||||||
/>
|
|
||||||
</HelpTooltip>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<BlacklistTable
|
<BlacklistTable
|
||||||
data={formattedData}
|
data={blacklistData}
|
||||||
selectedCoin={clickedItem}
|
|
||||||
handleDeleteEntry={handleDeleteEntry}
|
handleDeleteEntry={handleDeleteEntry}
|
||||||
errorMessage={errorMsg}
|
errorMessage={errorMsg}
|
||||||
setErrorMessage={setErrorMsg}
|
setErrorMessage={setErrorMsg}
|
||||||
|
|
@ -313,7 +267,6 @@ const Blacklist = () => {
|
||||||
setShowModal(false)
|
setShowModal(false)
|
||||||
}}
|
}}
|
||||||
errorMsg={errorMsg}
|
errorMsg={errorMsg}
|
||||||
selectedCoin={clickedItem}
|
|
||||||
addToBlacklist={addToBlacklist}
|
addToBlacklist={addToBlacklist}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,15 @@ const styles = {
|
||||||
content: {
|
content: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flex: 1,
|
flex: 1
|
||||||
marginLeft: spacer * 6
|
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
margin: [['auto', 0, spacer * 3, 'auto']]
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
margin: [['auto', 0, spacer * 3, 0]]
|
||||||
|
},
|
||||||
|
submit: {
|
||||||
|
margin: [['auto', 0, 0, 'auto']]
|
||||||
},
|
},
|
||||||
modalTitle: {
|
modalTitle: {
|
||||||
margin: [['auto', 0, 8.5, 'auto']]
|
margin: [['auto', 0, 8.5, 'auto']]
|
||||||
|
|
|
||||||
|
|
@ -14,31 +14,14 @@ import { H3 } from 'src/components/typography'
|
||||||
import styles from './Blacklist.styles'
|
import styles from './Blacklist.styles'
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const BlackListModal = ({
|
const BlackListModal = ({ onClose, addToBlacklist, errorMsg }) => {
|
||||||
onClose,
|
|
||||||
selectedCoin,
|
|
||||||
addToBlacklist,
|
|
||||||
errorMsg
|
|
||||||
}) => {
|
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const handleAddToBlacklist = address => {
|
const handleAddToBlacklist = address => {
|
||||||
if (selectedCoin.code === 'BCH' && !address.startsWith('bitcoincash:')) {
|
addToBlacklist(address)
|
||||||
address = 'bitcoincash:' + address
|
|
||||||
}
|
|
||||||
addToBlacklist(selectedCoin.code, address)
|
|
||||||
}
|
|
||||||
const placeholderAddress = {
|
|
||||||
BTC: '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD',
|
|
||||||
ETH: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
|
|
||||||
LTC: 'LPKvbjwV1Kaksktzkr7TMK3FQtQEEe6Wqa',
|
|
||||||
DASH: 'XqQ7gU8eM76rEfey726cJpT2RGKyJyBrcn',
|
|
||||||
ZEC: 't1KGyyv24eL354C9gjveBGEe8Xz9UoPKvHR',
|
|
||||||
BCH: 'qrd6za97wm03lfyg82w0c9vqgc727rhemg5yd9k3dm',
|
|
||||||
USDT: '0x5754284f345afc66a98fbb0a0afe71e0f007b949',
|
|
||||||
XMR:
|
|
||||||
'888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const placeholderAddress = '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
closeOnBackdropClick={true}
|
closeOnBackdropClick={true}
|
||||||
|
|
@ -61,26 +44,20 @@ const BlackListModal = ({
|
||||||
handleAddToBlacklist(address.trim())
|
handleAddToBlacklist(address.trim())
|
||||||
}}>
|
}}>
|
||||||
<Form id="address-form">
|
<Form id="address-form">
|
||||||
<H3 className={classes.modalTitle}>
|
<H3 className={classes.modalTitle}>Blacklist new address</H3>
|
||||||
{selectedCoin.display
|
|
||||||
? `Blacklist ${R.toLower(selectedCoin.display)} address`
|
|
||||||
: ''}
|
|
||||||
</H3>
|
|
||||||
<Field
|
<Field
|
||||||
name="address"
|
name="address"
|
||||||
fullWidth
|
fullWidth
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
label="Paste new address to blacklist here"
|
label="Paste new address to blacklist here"
|
||||||
placeholder={`ex: ${placeholderAddress[selectedCoin.code]}`}
|
placeholder={`ex: ${placeholderAddress}`}
|
||||||
component={TextInput}
|
component={TextInput}
|
||||||
/>
|
/>
|
||||||
{!R.isNil(errorMsg) && (
|
|
||||||
<ErrorMessage className={classes.error}>{errorMsg}</ErrorMessage>
|
|
||||||
)}
|
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
<div className={classes.footer}>
|
<div className={classes.footer}>
|
||||||
<Box display="flex" justifyContent="flex-end">
|
{!R.isNil(errorMsg) && <ErrorMessage>{errorMsg}</ErrorMessage>}
|
||||||
|
<Box className={classes.submit}>
|
||||||
<Link type="submit" form="address-form">
|
<Link type="submit" form="address-form">
|
||||||
Blacklist address
|
Blacklist address
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import React, { useState } from 'react'
|
||||||
import { DeleteDialog } from 'src/components/DeleteDialog'
|
import { DeleteDialog } from 'src/components/DeleteDialog'
|
||||||
import { IconButton } from 'src/components/buttons'
|
import { IconButton } from 'src/components/buttons'
|
||||||
import DataTable from 'src/components/tables/DataTable'
|
import DataTable from 'src/components/tables/DataTable'
|
||||||
import { Label1 } from 'src/components/typography'
|
|
||||||
import CopyToClipboard from 'src/pages/Transactions/CopyToClipboard'
|
import CopyToClipboard from 'src/pages/Transactions/CopyToClipboard'
|
||||||
import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg'
|
import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg'
|
||||||
|
|
||||||
|
|
@ -15,7 +14,6 @@ const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const BlacklistTable = ({
|
const BlacklistTable = ({
|
||||||
data,
|
data,
|
||||||
selectedCoin,
|
|
||||||
handleDeleteEntry,
|
handleDeleteEntry,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
setErrorMessage,
|
setErrorMessage,
|
||||||
|
|
@ -29,8 +27,8 @@ const BlacklistTable = ({
|
||||||
const elements = [
|
const elements = [
|
||||||
{
|
{
|
||||||
name: 'address',
|
name: 'address',
|
||||||
header: <Label1 className={classes.white}>{'Addresses'}</Label1>,
|
header: 'Address',
|
||||||
width: 800,
|
width: 1070,
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
view: it => (
|
view: it => (
|
||||||
|
|
@ -41,7 +39,7 @@ const BlacklistTable = ({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'deleteButton',
|
name: 'deleteButton',
|
||||||
header: <Label1 className={classes.white}>{'Delete'}</Label1>,
|
header: 'Delete',
|
||||||
width: 130,
|
width: 130,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
|
|
@ -57,14 +55,11 @@ const BlacklistTable = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const dataToShow = selectedCoin
|
|
||||||
? data[selectedCoin.code]
|
|
||||||
: data[R.keys(data)[0]]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DataTable
|
<DataTable
|
||||||
data={dataToShow}
|
data={data}
|
||||||
elements={elements}
|
elements={elements}
|
||||||
emptyText="No blacklisted addresses so far"
|
emptyText="No blacklisted addresses so far"
|
||||||
name="blacklistTable"
|
name="blacklistTable"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue