diff --git a/.github/workflows/deploy-libre.yaml b/.github/workflows/deploy-libre.yaml
index 4ec53693..80fdb762 100644
--- a/.github/workflows/deploy-libre.yaml
+++ b/.github/workflows/deploy-libre.yaml
@@ -39,8 +39,8 @@ jobs:
REACT_APP_DEFAULT_PRODUCER_LOGO: 'https://antelope.tools/images/libre.png'
REACT_APP_FOOTER_LINKS: '[{ "text": "Libre Website", "src": "https://libre.org/" },{ "text": "Libre Block Explorer", "src": "https://www.libreblocks.io/" },{"text": "Documentation","src": "https://libre-chain.gitbook.io/"},{"text": "Libre Network Monitor","src": "https://libre.antelope.tools"}]'
REACT_APP_EOS_RATE_LINK: ''
- REACT_APP_USE_REWARDS: 'false'
- REACT_APP_USE_VOTES: 'false'
+ REACT_APP_USE_REWARDS: 'true'
+ REACT_APP_USE_VOTES: 'true'
REACT_APP_HASURA_URL: 'https://graphql-libre.antelope.tools/v1/graphql'
REACT_APP_EOS_API_NETWORK_NAME: 'libre'
REACT_APP_EOS_API_NETWORK_LABEL: 'Libre Mainnet'
@@ -56,9 +56,9 @@ jobs:
REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000
REACT_APP_TOKEN_SYMBOL: 'LIBRE'
REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":1},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":2},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":3},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":4},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":5},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":1},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":2},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":3},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":4},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":5},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]'
- REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/stress-test"]'
+ REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/stress-test"]'
REACT_APP_BLOCK_EXPLORER_URL: 'https://www.libreblocks.io/tx/(transaction)'
- REACT_APP_STATE_HISTORY_ENABLED=: 'false'
+ REACT_APP_STATE_HISTORY_ENABLED: 'true'
REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8'
REACT_APP_PUBLIC_RE_CAPTCHA_KEY: ${{ secrets.REACT_APP_PUBLIC_RE_CAPTCHA_KEY }}
@@ -82,6 +82,11 @@ jobs:
# hapi
HAPI_EOS_API_NETWORK_NAME: libre
HAPI_EOS_API_ENDPOINTS: '["https://libre.edenia.cloud","https://libre.eosusa.io","https://api.libre.cryptolions.io"]'
+ HAPI_EOS_STATE_HISTORY_PLUGIN_ENDPOINT: 'ws://api-node.libre:8080'
+ HAPI_EOS_MISSED_BLOCKS_ENABLED: 'false'
+ HAPI_EOS_BLOCK_HISTORY_DAYS: 90
+ HAPI_EOS_MAX_CPU_BLOCK: 100000
+ HAPI_EOS_MAX_NET_BLOCK: 1048576
HAPI_EOS_API_CHAIN_ID: 38b1d7815474d0c60683ecbea321d723e83f5da6ae5f1c1f9fecc69d9ba96465
HAPI_EOS_BASE_ACCOUNT: ${{ secrets.HAPI_EOS_BASE_ACCOUNT }}
HAPI_EOS_BASE_ACCOUNT_PASSWORD: ${{ secrets.HAPI_EOS_BASE_ACCOUNT_PASSWORD }}
@@ -104,6 +109,7 @@ jobs:
HAPI_SYNC_PRODUCER_CPU_INTERVAL: '6'
HAPI_SYNC_PRODUCER_INFO_INTERVAL: '1'
HAPI_SYNC_SCHEDULE_HISTORY_INTERVAL: 86400
+ HAPI_SYNC_STATS_INTERVAL: 3600
HAPI_EOS_EXCHANGE_RATE_API: 'https://dashboard-api.libre.org/exchange-rates'
HAPI_COINGECKO_API_TOKEN_ID: LIBRE
HAPI_REWARDS_TOKEN: LIBRE
diff --git a/.github/workflows/deploy-wax-testnet.yaml b/.github/workflows/deploy-wax-testnet.yaml
index d9b1c0dc..c06f2a98 100644
--- a/.github/workflows/deploy-wax-testnet.yaml
+++ b/.github/workflows/deploy-wax-testnet.yaml
@@ -39,7 +39,7 @@ jobs:
REACT_APP_DEFAULT_PRODUCER_LOGO: 'https://antelope.tools/images/wax.jpg'
REACT_APP_FOOTER_LINKS: '[{ "text": "WAX Website", "src": "https://www.wax.io/" },{ "text": "WAX Block Explorer", "src": "https://wax-test.bloks.io/" },{"text": "Developer Guidelines","src": "https://developer.wax.io/"},{"text": "WAX Network Monitor","src": "https://antelope.tools"}]'
REACT_APP_EOS_RATE_LINK: ''
- REACT_APP_USE_REWARDS: 'false'
+ REACT_APP_USE_REWARDS: 'true'
REACT_APP_USE_VOTES: 'true'
REACT_APP_HASURA_URL: 'https://graphql-wax-testnet.antelope.tools/v1/graphql'
REACT_APP_EOS_API_NETWORK_NAME: 'wax-testnet'
diff --git a/.github/workflows/deploy-wax.yaml b/.github/workflows/deploy-wax.yaml
index 816920cd..372b3959 100644
--- a/.github/workflows/deploy-wax.yaml
+++ b/.github/workflows/deploy-wax.yaml
@@ -39,7 +39,7 @@ jobs:
REACT_APP_DEFAULT_PRODUCER_LOGO: 'https://antelope.tools/images/wax.jpg'
REACT_APP_FOOTER_LINKS: '[{ "text": "WAX Website", "src": "https://www.wax.io/" },{ "text": "WAX Block Explorer", "src": "https://wax.bloks.io" },{"text": "Developer Guidelines","src": "https://developer.wax.io/"},{"text": "WAX Network Monitor","src": "https://antelope.tools"}]'
REACT_APP_EOS_RATE_LINK: ''
- REACT_APP_USE_REWARDS: 'false'
+ REACT_APP_USE_REWARDS: 'true'
REACT_APP_USE_VOTES: 'true'
REACT_APP_HASURA_URL: 'https://graphql-wax.antelope.tools/v1/graphql'
REACT_APP_EOS_API_NETWORK_NAME: 'wax'
diff --git a/hapi/src/routes/create-faucet-account.route.js b/hapi/src/routes/create-faucet-account.route.js
index ef672b01..958b687b 100644
--- a/hapi/src/routes/create-faucet-account.route.js
+++ b/hapi/src/routes/create-faucet-account.route.js
@@ -6,7 +6,8 @@ const {
eosUtil,
axiosUtil,
googleRecaptchaEnterpriseUtil,
- getCreateAccountDataUtil
+ getCreateAccountDataUtil,
+ sleepFor
} = require('../utils')
module.exports = {
@@ -21,7 +22,7 @@ module.exports = {
throw Boom.badRequest('Are you a human?')
}
- await eosUtil.transact(
+ const transaction = await eosUtil.transact(
[
{
authorization: [
@@ -43,25 +44,35 @@ module.exports = {
eosConfig.faucet.password
)
+ await sleepFor(1)
+
const {
- data: { account_name: account, permissions }
+ data: { accounts }
} = await axiosUtil.instance.post(
- `${eosConfig.apiEndpoint}/v1/chain/get_account`,
+ `${eosConfig.apiEndpoint}/v1/chain/get_accounts_by_authorizers`,
{
- account_name: input.name
+ keys: [input.public_key]
}
)
- const keys = permissions[0]?.required_auth?.keys || []
- const key = keys[0]?.key
-
- if (account === input.name && key === input.public_key) {
- return { account }
+ if (!input.name) {
+ input.name = transaction?.processed?.action_traces[0]?.act?.data?.name
}
- return Boom.badData('Wrong key format')
+ const newAccount = accounts.find(
+ (account) => account.account_name === input.name || !input.name
+ )
+
+ if (!newAccount) throw new Error('Account creation failed')
+
+ return { account: newAccount.account_name }
} catch (err) {
- throw Boom.badRequest(err.message)
+ const errorDetail =
+ err?.response?.data?.error?.details[0]?.message?.substring(0, 11)
+
+ return errorDetail === 'unknown key'
+ ? Boom.badRequest('Account creation failed')
+ : Boom.badRequest(err.message)
}
},
options: {
diff --git a/webapp/src/components/ContractActionForm/index.js b/webapp/src/components/ContractActionForm/index.js
index 229f566e..92bc50ad 100644
--- a/webapp/src/components/ContractActionForm/index.js
+++ b/webapp/src/components/ContractActionForm/index.js
@@ -227,7 +227,7 @@ const ContractActionForm = ({ accountName, action, abi, onSubmitAction }) => {
InputProps={{
endAdornment: (
-
+
),
}}
diff --git a/webapp/src/components/ContractTables/index.js b/webapp/src/components/ContractTables/index.js
index 5ee5d728..f65c57ad 100644
--- a/webapp/src/components/ContractTables/index.js
+++ b/webapp/src/components/ContractTables/index.js
@@ -2,11 +2,10 @@ import React, { useState, useEffect, useCallback } from 'react'
import PropTypes from 'prop-types'
import { useTranslation } from 'react-i18next'
import { makeStyles } from '@mui/styles'
-import MenuItem from '@mui/material/MenuItem'
-import Select from '@mui/material/Select'
-import FormControl from '@mui/material/FormControl'
+import Autocomplete from '@mui/material/Autocomplete'
+import Checkbox from '@mui/material/Checkbox'
+import FormControlLabel from '@mui/material/FormControlLabel'
import TextField from '@mui/material/TextField'
-import InputLabel from '@mui/material/InputLabel'
import Button from '@mui/material/Button'
import RefreshIcon from '@mui/icons-material/Refresh'
@@ -24,26 +23,42 @@ const ContractTables = ({
onGetTableRows,
tableName,
}) => {
+ const keysTypes = [
+ 'i64',
+ 'i128',
+ 'i256',
+ 'float64',
+ 'float128',
+ 'sha256',
+ 'ripemd160',
+ 'name',
+ ]
const initData = {
table: '',
scope: '',
+ index: '',
+ keyType: keysTypes[0],
lowerBound: null,
upperBound: null,
limit: 10,
+ reverse: false,
}
const formFields = [
{ name: 'scope', type: 'text' },
- { name: 'lowerBound', type: 'number' },
- { name: 'upperBound', type: 'number' },
+ { name: 'index', type: 'text' },
+ { name: 'keyType', type: 'text', component: 'select', options: keysTypes },
+ { name: 'lowerBound', type: 'text' },
+ { name: 'upperBound', type: 'text' },
{ name: 'limit', type: 'number' },
]
- const DELAY = 300
+ const DELAY = 500
const { t } = useTranslation('contractTablesComponent')
const classes = useStyles()
const [tables, setTables] = useState([])
const [fields, setFields] = useState([])
const [filters, setFilters] = useState(initData)
+ const [selectedTable, setSelectedTable] = useState(tableName)
const debouncedFilter = useDebounceState(filters, DELAY)
const getValidValue = (value, type) => {
@@ -78,6 +93,9 @@ const ContractTables = ({
table: filters.table,
code: accountName,
json: true,
+ key_type: filters.keyType,
+ index_position: filters.index,
+ reverse: filters.reverse,
lower_bound: nextKey || filters.lowerBound,
upper_bound: filters.upperBound,
loadMore: !!nextKey,
@@ -86,6 +104,19 @@ const ContractTables = ({
[accountName, onGetTableRows, filters],
)
+ const handleTableSelect = (_event, value) => {
+ setSelectedTable(value || '')
+ if (tables.includes(value)) {
+ handleTableChange(value)
+ }
+ }
+
+ const handleFilterSelect = (newValue, name, type) => {
+ handleOnChange({
+ target: { name, type, value: newValue || '' },
+ })
+ }
+
useEffect(() => {
if (!abi) {
setTables([])
@@ -103,10 +134,12 @@ const ContractTables = ({
return
}
+ setSelectedTable(filters.table)
+
const tableType = abi.tables.find(
- (item) => item.name === filters.table,
+ item => item.name === filters.table,
)?.type
- const struct = abi.structs.find((struct) => struct.name === tableType)
+ const struct = abi.structs.find(struct => struct.name === tableType)
setFields(struct?.fields || [])
}, [filters.table, abi])
@@ -127,52 +160,86 @@ const ContractTables = ({
}, [debouncedFilter])
return (
-
+ <>
-
- {t('table')}
-
-
-
- {formFields.map(({ name, type }, index) => (
-
handleOnChange(event)}
+
+
(
+
+ )}
+ noOptionsText={t('noOptions')}
/>
- ))}
-
- {filters.table && (
-
- )}
+
+ {formFields.map(({ name, type, component, options }, index) =>
+ component === 'select' ? (
+ {
+ handleFilterSelect(value, name, type)
+ }}
+ onInputChange={(_e, value) => {
+ handleFilterSelect(value, name, type)
+ }}
+ renderInput={params => (
+
+ )}
+ noOptionsText={t('noOptions')}
+ />
+ ) : (
+ handleOnChange(event)}
+ />
+ ),
+ )}
+
+ {
+ setFilters(prev => ({
+ ...prev,
+ reverse: event.target.checked,
+ }))
+ }}
+ />
+ }
+ label={t('reverse')}
+ labelPlacement="top"
+ />
+
+
+
+ {filters.table && (
+
+ )}
+
-
+ >
)
}
diff --git a/webapp/src/components/ContractTables/styles.js b/webapp/src/components/ContractTables/styles.js
index 4b6fdc3a..be477cd8 100644
--- a/webapp/src/components/ContractTables/styles.js
+++ b/webapp/src/components/ContractTables/styles.js
@@ -4,15 +4,22 @@ export default (theme) => ({
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
+ gap: theme.spacing(1),
+ [theme.breakpoints.down('md')]: {
+ flexDirection: 'column'
+ }
},
formControl: {
display: 'block',
- width: '100%',
- minWidth: '180px',
- [theme.breakpoints.up('md')]: {
- width: '15%',
- marginRight: theme.spacing(2),
+ width: '12%',
+ marginRight: theme.spacing(2),
+ [theme.breakpoints.down('lg')]: {
+ width: '10%',
},
+ [theme.breakpoints.down('md')]: {
+ width: '100%',
+ minWidth: '180px',
+ }
},
refreshButton: {
[theme.breakpoints.up('md')]: {
@@ -28,9 +35,30 @@ export default (theme) => ({
padding: theme.spacing(4),
},
tableEmpty: {
- [theme.breakpoints.up('md')]: {
- width: '150px !important',
+ [theme.breakpoints.down('lg')]: {
+ width: '100px !important',
},
+ [theme.breakpoints.down('md')]: {
+ width: '100% !important',
+ },
+ width: '120px !important',
display: 'inline-block',
},
+ fieldsContainer: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ width: '80%',
+ gap: '8px',
+ },
+ textField: {
+ width: '200px',
+ [theme.breakpoints.down('md')]: {
+ width: '100%'
+ }
+ },
+ checkBox: {
+ '& .MuiCheckbox-root': {
+ padding: `${theme.spacing(1)} !important`,
+ }
+ }
})
diff --git a/webapp/src/components/EndpointsTable/styles.js b/webapp/src/components/EndpointsTable/styles.js
index c5e8ebf5..34b7ad03 100644
--- a/webapp/src/components/EndpointsTable/styles.js
+++ b/webapp/src/components/EndpointsTable/styles.js
@@ -3,6 +3,14 @@ export default (theme) => ({
display: 'flex',
justifyContent: 'space-between',
maxWidth: '250px',
+ wordBreak: 'break-all',
+ [theme.breakpoints.down('lg')]: {
+ maxWidth: '300px',
+ wordBreak: 'normal',
+ },
+ [theme.breakpoints.up('xl')]: {
+ maxWidth: '350px',
+ }
},
titleCell: {
display: 'flex',
diff --git a/webapp/src/components/ProducersChart/index.js b/webapp/src/components/ProducersChart/index.js
index 0df0d56f..ba02b5b2 100644
--- a/webapp/src/components/ProducersChart/index.js
+++ b/webapp/src/components/ProducersChart/index.js
@@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next'
import { formatWithThousandSeparator, onImgError } from '../../utils'
import isLogoValid from '../../utils/validate-image'
-import { generalConfig } from '../../config'
+import { eosConfig, generalConfig } from '../../config'
import styles from './styles'
@@ -192,7 +192,9 @@ const CustomTooltip = memo(({ active, payload }) => {
{t('rewards')}:{' '}
{' '}
- {formatWithThousandSeparator(payload[0].payload.rewards, 2)}
+ {`${formatWithThousandSeparator(payload[0].payload.rewards, 2)} ${
+ eosConfig.tokenSymbol
+ }`}
)}
diff --git a/webapp/src/components/TransactionsHistory/index.js b/webapp/src/components/TransactionsHistory/index.js
index fc124f95..fba5e5e4 100644
--- a/webapp/src/components/TransactionsHistory/index.js
+++ b/webapp/src/components/TransactionsHistory/index.js
@@ -17,17 +17,17 @@ import styles from './styles'
const useStyles = makeStyles(styles)
-const BodyGraphValue = ({ loading, value, classes, href }) => {
+const BodyGraphValue = ({ loading, value, classes, links }) => {
if (loading) return
return (
{value}
- {href && (
-
+ {links && links.map((href, index) => (
+
- )}
+ ))}
)
}
@@ -60,9 +60,7 @@ const TransactionsHistory = ({ t, nodesChildren }) => {
value={data?.stats[0]?.tps_all_time_high?.transactions_count}
loading={loading}
classes={classes}
- href={getBlockNumUrl(
- data?.stats?.[0]?.tps_all_time_high?.blocks[0],
- )}
+ links={data?.stats?.[0]?.tps_all_time_high?.blocks.map(block => getBlockNumUrl(block))}
/>
@@ -70,9 +68,7 @@ const TransactionsHistory = ({ t, nodesChildren }) => {
getBlockNumUrl(block))}
loading={loading}
/>
@@ -81,9 +77,7 @@ const TransactionsHistory = ({ t, nodesChildren }) => {
getBlockNumUrl(block))}
loading={loading}
/>
diff --git a/webapp/src/gql/faucet.gql.js b/webapp/src/gql/faucet.gql.js
index ad1670dc..8ea73834 100644
--- a/webapp/src/gql/faucet.gql.js
+++ b/webapp/src/gql/faucet.gql.js
@@ -1,8 +1,12 @@
import gql from 'graphql-tag'
-export const CREATE_ACCOUNT_MUTATION = gql`
- mutation ($token: String!, $public_key: String!, $name: String) {
- createAccount(token: $token, public_key: $public_key, name: $name) {
+export const CREATE_ACCOUNT_MUTATION = (includeName = true) => gql`
+ mutation ($token: String!, $public_key: String! ${
+ includeName ? ', $name: String' : ''
+ }) {
+ createAccount(token: $token, public_key: $public_key ${
+ includeName ? ', name: $name' : ''
+ }) {
account
}
}
diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json
index ad171e7e..220a3c84 100644
--- a/webapp/src/language/en.json
+++ b/webapp/src/language/en.json
@@ -139,8 +139,8 @@
"tpsAllTimeHigh": "TPS All Time High",
"cpuUtilization": "CPU Usage",
"netUtilization": "NET Usage",
- "cpuUtilizationAllTimeHigh": "CPU Usage All Time High",
- "networkUtilizationAllTimeHigh": "NET Usage All Time High",
+ "cpuUtilizationAllTimeHigh": "CPU Usage in TPS All Time High",
+ "networkUtilizationAllTimeHigh": "NET Usage in TPS All Time High",
"transactionsPerSecond": "Transactions per Second",
"transactionsPerBlock": "Transactions per Block",
"nodes": "Nodes",
@@ -328,6 +328,8 @@
"upperBound": "Upper Bound",
"limit": "Limit",
"refreshData": "Refresh Data",
+ "index": "Index Position",
+ "keyType": "Index Type",
"loadMore": "Load More",
"emptyTable": "Empty Table"
},
diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json
index c834bdd4..2ca8080e 100644
--- a/webapp/src/language/es.json
+++ b/webapp/src/language/es.json
@@ -143,8 +143,8 @@
"secondsAgo": "Hace Segundos",
"cpuUtilization": "Uso de CPU",
"netUtilization": "Uso de NET",
- "cpuUtilizationAllTimeHigh": "Máxima uso de CPU",
- "networkUtilizationAllTimeHigh": "Máxima uso de NET",
+ "cpuUtilizationAllTimeHigh": "Uso de CPU en TPS máximo histórico",
+ "networkUtilizationAllTimeHigh": "Uso de NET en TPS máximo histórico",
"tpsAllTimeHigh": "TPS máximo histórico",
"transactionsPerSecond": "Transacciones por segundo",
"transactionsPerBlock": "Transacciones por bloque",
@@ -331,9 +331,11 @@
},
"contractTablesComponent": {
"table": "Tabla",
- "scope": "Alcance",
+ "scope": "Ámbito",
"lowerBound": "Límite inferior",
"upperBound": "Límite superior",
+ "index": "Posición del Índice",
+ "keyType": "Tipo del Índice",
"limit": "Límite",
"refreshData": "Actualizar Datos",
"loadMore": "Carga Más",
diff --git a/webapp/src/routes/Accounts/useAccountState.js b/webapp/src/routes/Accounts/useAccountState.js
index c55fd0bb..bab77ba5 100644
--- a/webapp/src/routes/Accounts/useAccountState.js
+++ b/webapp/src/routes/Accounts/useAccountState.js
@@ -61,7 +61,9 @@ const useAccountState = () => {
try {
const actionError = JSON.parse(error?.message).error.details[0].message
- return actionError ? `${resultRequested} ${t('notFound')}` : ''
+ return actionError?.substring(0, 11) === 'unknown key'
+ ? `${resultRequested} ${t('notFound')}`
+ : actionError
} catch (error) {
return t('unknownError')
}
diff --git a/webapp/src/routes/Faucet/index.js b/webapp/src/routes/Faucet/index.js
index 5e46d716..ce4c5236 100644
--- a/webapp/src/routes/Faucet/index.js
+++ b/webapp/src/routes/Faucet/index.js
@@ -30,7 +30,7 @@ const Faucet = () => {
const [createAccountValues, setCreateAccountValues] = useState({})
const [transferTokensTransaction, setTransferTokensTransaction] = useState('')
const [createFaucetAccount, { loading: loadingCreateAccount }] = useMutation(
- CREATE_ACCOUNT_MUTATION,
+ CREATE_ACCOUNT_MUTATION(eosConfig.networkName !== 'ultra-testnet'),
)
const [transferFaucetTokens, { loading: loadingTransferFaucetTokens }] =
useMutation(TRANFER_FAUCET_TOKENS_MUTATION)
@@ -39,14 +39,25 @@ const Faucet = () => {
const createAccount = async () => {
const reCaptchaToken = await executeRecaptcha?.('submit')
- if (eosConfig.networkName === 'libre-testnet') {
- if (
- !reCaptchaToken ||
- (!createAccountValues.publicKey && !createAccountValues.accountName)
- )
- return
- } else {
- if (!reCaptchaToken || !createAccountValues.publicKey) return
+ if (
+ !reCaptchaToken ||
+ !createAccountValues.publicKey ||
+ (eosConfig.networkName !== 'ultra-testnet' &&
+ !createAccountValues.accountName)
+ ) {
+ showMessage({
+ type: 'error',
+ content: 'Fill out the fields to create an account',
+ })
+ return
+ }
+
+ if (!isValidAccountName(createAccountValues.accountName)) {
+ showMessage({
+ type: 'error',
+ content: 'Please enter a valid account name',
+ })
+ return
}
try {
@@ -58,7 +69,7 @@ const Faucet = () => {
variables: {
token: reCaptchaToken,
public_key: createAccountValues.publicKey,
- name: createAccountValues.accountName || '',
+ name: createAccountValues.accountName,
},
})
@@ -71,10 +82,9 @@ const Faucet = () => {
),
})
} catch (err) {
- const errorMessage = err.message.replace(
- 'GraphQL error: assertion failure with message: ',
- '',
- )
+ const errorMessage = err.message
+ .replace('GraphQL error:', '')
+ .replace('assertion failure with message: ', '')
showMessage({
type: 'error',
@@ -91,6 +101,14 @@ const Faucet = () => {
if (!reCaptchaToken || !account) return
+ if (!isValidAccountName(account)) {
+ showMessage({
+ type: 'error',
+ content: 'Please enter a valid account name',
+ })
+ return
+ }
+
try {
const result = await transferFaucetTokens({
variables: {
@@ -128,6 +146,12 @@ const Faucet = () => {
setAccount('')
}
+ const isValidAccountName = name => {
+ const regex = /^[.12345abcdefghijklmnopqrstuvwxyz]+$/i
+
+ return name?.length < 13 && regex.test(name)
+ }
+
return (
@@ -147,9 +171,11 @@ const Faucet = () => {
...{ publicKey: e.target.value },
})
}
+ error={!createAccountValues.publicKey}
+ required
/>
- {eosConfig.networkName === 'libre-testnet' && (
+ {eosConfig.networkName !== 'ultra-testnet' && (
{
...{ accountName: e.target.value },
})
}
+ error={!isValidAccountName(createAccountValues.accountName)}
+ required
/>
)}
@@ -195,10 +223,12 @@ const Faucet = () => {
setAccount(e.target.value)}
+ error={!isValidAccountName(account)}
+ required
/>
diff --git a/webapp/src/utils/get-blocknum-url.js b/webapp/src/utils/get-blocknum-url.js
index dbe9c1d6..3c7f8062 100644
--- a/webapp/src/utils/get-blocknum-url.js
+++ b/webapp/src/utils/get-blocknum-url.js
@@ -7,9 +7,10 @@ export const getBlockNumUrl = (blockNum) => {
return (
eosConfig.blockExplorerUrl
+ .replace('(transaction)', blockNum)
+ .replace('tx', 'block')
.replace('transaction', 'block')
// eslint-disable-next-line
- .replace('(transaction)', blockNum)
)
}