From a5ebf6e101c6b5d12991414b14a88cef8056d4fe Mon Sep 17 00:00:00 2001 From: pandablue0809 Date: Fri, 19 Sep 2025 06:29:12 +0900 Subject: [PATCH 1/3] add explanation text --- pages/services/account-settings.js | 207 ++++++++++++++++++++-- styles/pages/account-settings.module.scss | 29 +++ 2 files changed, 218 insertions(+), 18 deletions(-) diff --git a/pages/services/account-settings.js b/pages/services/account-settings.js index c1809a37e..1a32085d0 100644 --- a/pages/services/account-settings.js +++ b/pages/services/account-settings.js @@ -73,6 +73,115 @@ export default function AccountSettings({ const [currentTickSize, setCurrentTickSize] = useState(null) const [walletLocatorInput, setWalletLocatorInput] = useState('') const [currentWalletLocator, setCurrentWalletLocator] = useState('') + + // Validation states + const [messageKeyValidation, setMessageKeyValidation] = useState({ isValid: true, message: '' }) + const [walletLocatorValidation, setWalletLocatorValidation] = useState({ isValid: true, message: '' }) + const [tickSizeValidation, setTickSizeValidation] = useState({ isValid: true, message: '' }) + + // Validation functions + const validateMessageKey = (value) => { + const trimmed = value.trim() + + if (!trimmed) { + return { isValid: true, message: '' } // Empty is valid (will be cleared) + } + + const isHex = /^[0-9a-fA-F]+$/.test(trimmed) + + if (!isHex) { + return { + isValid: false, + message: 'Must contain only hexadecimal characters (0-9, a-f, A-F)' + } + } + + if (trimmed.length % 2 !== 0) { + return { + isValid: false, + message: 'Must have an even number of characters (pairs of hex digits)' + } + } + + if (trimmed.length < 32) { + return { + isValid: false, + message: 'Must be at least 32 characters (16 bytes)' + } + } + + return { isValid: true, message: 'Valid hex-encoded public key' } + } + + const validateWalletLocator = (value) => { + const trimmed = value.trim() + + if (!trimmed) { + return { isValid: true, message: '' } // Empty is valid (will be cleared) + } + + const isHex = /^[0-9a-fA-F]+$/.test(trimmed) + + if (!isHex) { + return { + isValid: false, + message: 'Must contain only hexadecimal characters (0-9, a-f, A-F)' + } + } + + if (trimmed.length !== 64) { + return { + isValid: false, + message: `Must be exactly 64 characters (current: ${trimmed.length})` + } + } + + return { isValid: true, message: 'Valid 64-character hex string' } + } + + const validateTickSize = (value) => { + const trimmed = value.trim() + + if (!trimmed) { + return { isValid: true, message: '' } // Empty is valid (will be cleared) + } + + const numValue = Number(trimmed) + + if (isNaN(numValue)) { + return { + isValid: false, + message: 'Must be a valid number' + } + } + + if (!Number.isInteger(numValue)) { + return { + isValid: false, + message: 'Must be a whole number (integer)' + } + } + + if (numValue < 0) { + return { + isValid: false, + message: 'Must be 0 or positive' + } + } + + if (numValue === 0) { + return { isValid: true, message: 'Valid (will clear tick size)' } + } + + if (numValue < 3 || numValue > 15) { + return { + isValid: false, + message: 'Must be between 3 and 15 (or 0 to clear)' + } + } + + return { isValid: true, message: 'Valid tick size' } + } // TF flags state const [tfFlags, setTfFlags] = useState(null) @@ -554,8 +663,24 @@ export default function AccountSettings({ const handleSetMessageKey = () => { const value = messageKeyInput.trim() const isHex = /^[0-9a-fA-F]+$/.test(value) - if (!value || !isHex || value.length % 2 !== 0) { - setErrorMessage('Please enter a valid hex-encoded MessageKey.') + + if (!value) { + setErrorMessage('MessageKey cannot be empty. Please enter a hex-encoded public key.') + return + } + + if (!isHex) { + setErrorMessage('MessageKey must contain only hexadecimal characters (0-9, a-f, A-F).') + return + } + + if (value.length % 2 !== 0) { + setErrorMessage('MessageKey must have an even number of characters (pairs of hex digits). Current length: ' + value.length + '.') + return + } + + if (value.length < 32) { + setErrorMessage('MessageKey must be at least 32 characters (16 bytes). Current length: ' + value.length + '.') return } const tx = { @@ -699,9 +824,20 @@ export default function AccountSettings({ const handleSetWalletLocator = () => { const value = walletLocatorInput.trim() - const isValid = /^[0-9a-fA-F]{64}$/.test(value) - if (!isValid) { - setErrorMessage('Please enter a valid WalletLocator (64 hexadecimal characters).') + const isHex = /^[0-9a-fA-F]+$/.test(value) + + if (!value) { + setErrorMessage('WalletLocator cannot be empty. Please enter a 64-character hexadecimal string.') + return + } + + if (!isHex) { + setErrorMessage('WalletLocator must contain only hexadecimal characters (0-9, a-f, A-F).') + return + } + + if (value.length !== 64) { + setErrorMessage('WalletLocator must be exactly 64 characters long. Current length: ' + value.length + '.') return } const tx = { @@ -1109,21 +1245,34 @@ export default function AccountSettings({ Clear )} -
setMessageKeyInput(e.target.value)} + onChange={(e) => { + const value = e.target.value + setMessageKeyInput(value) + setMessageKeyValidation(validateMessageKey(value)) + }} type="text" disabled={!account?.address} /> - Provide a hex-encoded public key; clearing removes it from the ledger. + Provide a hex-encoded public key (minimum 32 characters, even number of hex digits). Used for encrypted messaging. + {messageKeyInput && messageKeyValidation.message && ( +
+ {messageKeyValidation.message} +
+ )}
@@ -1177,22 +1326,35 @@ export default function AccountSettings({ )}
-
setTickSizeInput(e.target.value)} + onChange={(e) => { + const value = e.target.value + setTickSizeInput(value) + setTickSizeValidation(validateTickSize(value)) + }} type="text" inputMode="numeric" disabled={!account?.address} /> Controls significant digits for order book prices. 0 clears. + {tickSizeInput && tickSizeValidation.message && ( +
+ {tickSizeValidation.message} +
+ )}
@@ -1217,7 +1379,7 @@ export default function AccountSettings({ @@ -1225,15 +1387,24 @@ export default function AccountSettings({
setWalletLocatorInput(e.target.value)} + onChange={(e) => { + const value = e.target.value + setWalletLocatorInput(value) + setWalletLocatorValidation(validateWalletLocator(value)) + }} type="text" disabled={!account?.address} maxLength={64} /> - Optional hash locator for your wallet application. + Optional 64-character hexadecimal hash locator for your wallet application. + {walletLocatorInput && walletLocatorValidation.message && ( +
+ {walletLocatorValidation.message} +
+ )}
diff --git a/styles/pages/account-settings.module.scss b/styles/pages/account-settings.module.scss index 3bf51ccc2..a9e7fdb7e 100644 --- a/styles/pages/account-settings.module.scss +++ b/styles/pages/account-settings.module.scss @@ -141,6 +141,35 @@ opacity: 0.7; } } + + .input-error { + border-color: #dc3545 !important; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important; + } + + .input-valid { + border-color: #28a745 !important; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25) !important; + } + + .validation-message { + margin-top: 0.5rem; + font-size: 12px; + padding: 4px 8px; + border-radius: 4px; + + &.validation-error { + color: #dc3545; + background-color: rgba(220, 53, 69, 0.1); + border: 1px solid rgba(220, 53, 69, 0.2); + } + + &.validation-success { + color: #28a745; + background-color: rgba(40, 167, 69, 0.1); + border: 1px solid rgba(40, 167, 69, 0.2); + } + } } .advanced-options { From 5fa654c76d0a143b3b27872268dfe797e1c0059f Mon Sep 17 00:00:00 2001 From: pandablue0809 Date: Tue, 30 Sep 2025 20:49:08 +0900 Subject: [PATCH 2/3] optimise the code --- pages/services/account-settings.js | 134 +++++++++++++---------------- 1 file changed, 62 insertions(+), 72 deletions(-) diff --git a/pages/services/account-settings.js b/pages/services/account-settings.js index 1a32085d0..b90bcefc4 100644 --- a/pages/services/account-settings.js +++ b/pages/services/account-settings.js @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react' import Link from 'next/link' import { useTranslation } from 'next-i18next' import axios from 'axios' -import { xahauNetwork, explorerName, nativeCurrency, isAddressValid, encode, isEmailValid, md5 } from '../../utils' +import { xahauNetwork, explorerName, nativeCurrency, isAddressValid, encode, isEmailValid, md5, isHexString } from '../../utils' import { multiply, subtract } from '../../utils/calc' import SEO from '../../components/SEO' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' @@ -79,64 +79,71 @@ export default function AccountSettings({ const [walletLocatorValidation, setWalletLocatorValidation] = useState({ isValid: true, message: '' }) const [tickSizeValidation, setTickSizeValidation] = useState({ isValid: true, message: '' }) - // Validation functions - const validateMessageKey = (value) => { + const validateInput = (value, options = {}) => { + const { + allowEmpty = true, + evenLength = true, + minChars, + exactChars, + successMessage = 'Valid input' + } = options + const trimmed = value.trim() - + if (!trimmed) { - return { isValid: true, message: '' } // Empty is valid (will be cleared) + return { isValid: allowEmpty, message: '' } } - - const isHex = /^[0-9a-fA-F]+$/.test(trimmed) - - if (!isHex) { - return { - isValid: false, - message: 'Must contain only hexadecimal characters (0-9, a-f, A-F)' + + if (!isHexString(trimmed)) { + return { + isValid: false, + message: 'Must contain only hexadecimal characters (0-9, a-f, A-F)' } } - - if (trimmed.length % 2 !== 0) { - return { - isValid: false, - message: 'Must have an even number of characters (pairs of hex digits)' + + if (evenLength && trimmed.length % 2 !== 0) { + return { + isValid: false, + message: 'Must have an even number of characters (pairs of hex digits)' } } - - if (trimmed.length < 32) { - return { - isValid: false, - message: 'Must be at least 32 characters (16 bytes)' + + if (typeof exactChars === 'number') { + if (trimmed.length !== exactChars) { + return { + isValid: false, + message: `Must be exactly ${exactChars} characters (current: ${trimmed.length})` + } + } + } else if (typeof minChars === 'number') { + if (trimmed.length < minChars) { + return { + isValid: false, + message: `Must be at least ${minChars} characters (${minChars / 2} bytes)` + } } } - - return { isValid: true, message: 'Valid hex-encoded public key' } + + return { isValid: true, message: successMessage } + } + + // Validation functions + const validateMessageKey = (value) => { + return validateInput(value, { + allowEmpty: true, + evenLength: true, + minChars: 32, + successMessage: 'Valid hex-encoded public key' + }) } const validateWalletLocator = (value) => { - const trimmed = value.trim() - - if (!trimmed) { - return { isValid: true, message: '' } // Empty is valid (will be cleared) - } - - const isHex = /^[0-9a-fA-F]+$/.test(trimmed) - - if (!isHex) { - return { - isValid: false, - message: 'Must contain only hexadecimal characters (0-9, a-f, A-F)' - } - } - - if (trimmed.length !== 64) { - return { - isValid: false, - message: `Must be exactly 64 characters (current: ${trimmed.length})` - } - } - - return { isValid: true, message: 'Valid 64-character hex string' } + return validateInput(value, { + allowEmpty: true, + evenLength: true, + exactChars: 64, + successMessage: 'Valid 64-character hex string' + }) } const validateTickSize = (value) => { @@ -662,25 +669,14 @@ export default function AccountSettings({ const handleSetMessageKey = () => { const value = messageKeyInput.trim() - const isHex = /^[0-9a-fA-F]+$/.test(value) - if (!value) { setErrorMessage('MessageKey cannot be empty. Please enter a hex-encoded public key.') return } - - if (!isHex) { - setErrorMessage('MessageKey must contain only hexadecimal characters (0-9, a-f, A-F).') - return - } - - if (value.length % 2 !== 0) { - setErrorMessage('MessageKey must have an even number of characters (pairs of hex digits). Current length: ' + value.length + '.') - return - } - - if (value.length < 32) { - setErrorMessage('MessageKey must be at least 32 characters (16 bytes). Current length: ' + value.length + '.') + + const validation = validateMessageKey(value) + if (!validation.isValid) { + setErrorMessage(`MessageKey ${validation.message}`) return } const tx = { @@ -824,20 +820,14 @@ export default function AccountSettings({ const handleSetWalletLocator = () => { const value = walletLocatorInput.trim() - const isHex = /^[0-9a-fA-F]+$/.test(value) - if (!value) { setErrorMessage('WalletLocator cannot be empty. Please enter a 64-character hexadecimal string.') return } - - if (!isHex) { - setErrorMessage('WalletLocator must contain only hexadecimal characters (0-9, a-f, A-F).') - return - } - - if (value.length !== 64) { - setErrorMessage('WalletLocator must be exactly 64 characters long. Current length: ' + value.length + '.') + + const validation = validateWalletLocator(value) + if (!validation.isValid) { + setErrorMessage(`WalletLocator ${validation.message}`) return } const tx = { From 57823b637a143eaa12fbc9171cc7f603ec8b1df6 Mon Sep 17 00:00:00 2001 From: pandablue0809 Date: Mon, 6 Oct 2025 10:22:48 +0900 Subject: [PATCH 3/3] fix setting the messageKey --- pages/services/account-settings.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pages/services/account-settings.js b/pages/services/account-settings.js index b90bcefc4..1ef72d1ac 100644 --- a/pages/services/account-settings.js +++ b/pages/services/account-settings.js @@ -94,7 +94,7 @@ export default function AccountSettings({ return { isValid: allowEmpty, message: '' } } - if (!isHexString(trimmed)) { + if (!isHexString(trimmed.toUpperCase())) { return { isValid: false, message: 'Must contain only hexadecimal characters (0-9, a-f, A-F)' @@ -129,11 +129,22 @@ export default function AccountSettings({ // Validation functions const validateMessageKey = (value) => { + const trimmed = value.trim() + // Check the first byte for valid key type prefixes + const firstByte = trimmed.substring(0, 2).toUpperCase() + const validPrefixes = ['02', '03', 'ED'] + + if (!validPrefixes.includes(firstByte)) { + return { + isValid: false, + message: `First byte must be 02 or 03 for secp256k1 keys, or ED for Ed25519 keys. Current: 0x${firstByte}` + } + } return validateInput(value, { allowEmpty: true, evenLength: true, - minChars: 32, - successMessage: 'Valid hex-encoded public key' + exactChars: 66, + successMessage: 'Valid 66-character hex string' }) } @@ -1256,8 +1267,9 @@ export default function AccountSettings({ }} type="text" disabled={!account?.address} + maxLength={66} /> - Provide a hex-encoded public key (minimum 32 characters, even number of hex digits). Used for encrypted messaging. + Provide a hex-encoded public key (exactly 66 characters/33 bytes). First byte must be 0x02 or 0x03 for secp256k1 keys, or 0xED for Ed25519 keys. Used for encrypted messaging. {messageKeyInput && messageKeyValidation.message && (
{messageKeyValidation.message}