Skip to content

Commit

Permalink
feat(wallet): add EIP-55 checksum address checks in Send widget
Browse files Browse the repository at this point in the history
  • Loading branch information
onyb committed Dec 15, 2021
1 parent a36db31 commit a40e050
Show file tree
Hide file tree
Showing 14 changed files with 78 additions and 4 deletions.
4 changes: 4 additions & 0 deletions components/brave_wallet/browser/brave_wallet_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,10 @@ constexpr webui::LocalizedString kLocalizedStrings[] = {
{"braveWalletSameAddressError", IDS_BRAVE_WALLET_SAME_ADDRESS_ERROR},
{"braveWalletContractAddressError",
IDS_BRAVE_WALLET_CONTRACT_ADDRESS_ERROR},
{"braveWalletAddressMissingChecksumInfoWarning",
IDS_BRAVE_WALLET_ADDRESS_MISSING_CHECKSUM_INFO_WARNING},
{"braveWalletNotValidChecksumAddressError",
IDS_BRAVE_WALLET_NOT_VALID_CHECKSUM_ADDRESS_ERROR},
{"braveWalletQueueOf", IDS_BRAVE_WALLET_QUEUE_OF},
{"braveWalletQueueNext", IDS_BRAVE_WALLET_QUEUE_NEXT},
{"braveWalletQueueFirst", IDS_BRAVE_WALLET_QUEUE_FIRST},
Expand Down
5 changes: 5 additions & 0 deletions components/brave_wallet_ui/common/async/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ export const getBalance = (address: string): Promise<string> => {
})
}

export async function getChecksumEthAddress (value: string) {
const { keyringController } = getAPIProxy()
return (await keyringController.getChecksumEthAddress(value))
}

export async function isStrongPassword (value: string) {
const apiProxy = getAPIProxy()
return (await apiProxy.keyringController.isStrongPassword(value)).result
Expand Down
39 changes: 35 additions & 4 deletions components/brave_wallet_ui/common/hooks/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
ER20TransferParams,
SendTransactionParams,
ERC721TransferFromParams,
ERCToken
ERCToken,
GetChecksumEthAddressReturnInfo
} from '../../constants/types'
import { isValidAddress } from '../../utils/address-utils'
import { getLocale } from '../../../common/locale'
Expand All @@ -21,6 +22,7 @@ import { toWeiHex } from '../../utils/format-balances'
export default function useSend (
findENSAddress: (address: string) => Promise<GetEthAddrReturnInfo>,
findUnstoppableDomainAddress: (address: string) => Promise<GetEthAddrReturnInfo>,
getChecksumEthAddress: (address: string) => Promise<GetChecksumEthAddressReturnInfo>,
sendAssetOptions: AccountAssetOptionType[],
selectedAccount: WalletAccountType,
sendERC20Transfer: SimpleActionCreator<ER20TransferParams>,
Expand All @@ -32,6 +34,7 @@ export default function useSend (
const [toAddressOrUrl, setToAddressOrUrl] = React.useState('')
const [toAddress, setToAddress] = React.useState('')
const [addressError, setAddressError] = React.useState('')
const [addressWarning, setAddressWarning] = React.useState('')
const [sendAmount, setSendAmount] = React.useState('')

React.useEffect(() => {
Expand Down Expand Up @@ -77,6 +80,7 @@ export default function useSend (
findENSAddress(toAddressOrUrl).then((value: GetEthAddrReturnInfo) => {
if (value.success) {
setAddressError('')
setAddressWarning('')
setToAddress(value.address)
return
}
Expand All @@ -91,6 +95,7 @@ export default function useSend (
findUnstoppableDomainAddress(toAddressOrUrl).then((value: GetEthAddrReturnInfo) => {
if (value.success) {
setAddressError('')
setAddressWarning('')
setToAddress(value.address)
return
}
Expand All @@ -102,34 +107,59 @@ export default function useSend (
// If value is the same as the selectedAccounts Wallet Address
if (valueToLowerCase === selectedAccount?.address?.toLowerCase()) {
setToAddress(toAddressOrUrl)
setAddressWarning('')
setAddressError(getLocale('braveWalletSameAddressError'))
return
}

// If value is a Tokens Contract Address
if (fullTokenList.some(token => token.contractAddress.toLowerCase() === valueToLowerCase)) {
setToAddress(toAddressOrUrl)
setAddressWarning('')
setAddressError(getLocale('braveWalletContractAddressError'))
return
}

// If value starts with 0x, will check if it's a valid address
if (valueToLowerCase.startsWith('0x')) {
setToAddress(toAddressOrUrl)
isValidAddress(toAddressOrUrl, 20)
? setAddressError('')
: setAddressError(getLocale('braveWalletNotValidEthAddress'))
if (!isValidAddress(toAddressOrUrl, 20)) {
setAddressWarning('')
setAddressError(getLocale('braveWalletNotValidEthAddress'))
return
}

getChecksumEthAddress(toAddressOrUrl).then((value: GetChecksumEthAddressReturnInfo) => {
const { checksumAddress } = value
if (checksumAddress === toAddressOrUrl) {
setAddressWarning('')
setAddressError('')
return
}

if ([toAddressOrUrl.toLowerCase(), toAddressOrUrl.toUpperCase()].includes(toAddressOrUrl)) {
setAddressError('')
setAddressWarning(getLocale('braveWalletAddressMissingChecksumInfoWarning'))
return
}

setAddressWarning('')
setAddressError(getLocale('braveWalletNotValidChecksumAddressError'))
}).catch(e => console.log(e))

return
}

// Resets State
if (toAddressOrUrl === '') {
setAddressError('')
setAddressWarning('')
setToAddress('')
return
}

// Fallback error state
setAddressWarning('')
setAddressError(getLocale('braveWalletNotValidAddress'))
}, [toAddressOrUrl, selectedAccount])

Expand Down Expand Up @@ -168,6 +198,7 @@ export default function useSend (
toAddress,
sendAmount,
addressError,
addressWarning,
selectedSendAsset
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface Props {
toAddressOrUrl: string
toAddress: string
addressError: string
addressWarning: string
onSubmit: () => void
onInputChange: (value: string, name: string) => void
onChangeSendView: (view: BuySendSwapViewTypes, option?: ToOrFromType) => void
Expand All @@ -34,6 +35,7 @@ function Send (props: Props) {
toAddressOrUrl,
toAddress,
addressError,
addressWarning,
onInputChange,
onSelectPresetAmount,
onSubmit,
Expand Down Expand Up @@ -74,6 +76,7 @@ function Send (props: Props) {
onInputChange={onInputChange}
toAddressOrUrl={toAddressOrUrl}
addressError={addressError}
addressWarning={addressWarning}
toAddress={toAddress}
inputName='address'
onPaste={onPasteFromClipboard}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export interface Props {
selectedAsset?: AccountAssetOptionType
selectedAssetInputAmount?: string
addressError?: string
addressWarning?: string
toAddressOrUrl?: string
toAddress?: string
inputName?: string
Expand Down Expand Up @@ -87,6 +88,7 @@ function SwapInputComponent (props: Props) {
selectedAssetInputAmount,
inputName,
addressError,
addressWarning,
toAddressOrUrl,
toAddress,
orderType,
Expand Down Expand Up @@ -348,6 +350,11 @@ function SwapInputComponent (props: Props) {
{componentType === 'toAddress' && addressError &&
<WarningText>{addressError}</WarningText>
}

{componentType === 'toAddress' && addressWarning &&
<WarningText>{addressWarning}</WarningText>
}

{componentType === 'toAddress' && toAddress !== toAddressOrUrl && !addressError &&
<AddressConfirmationText>{reduceAddress(toAddress ?? '')}</AddressConfirmationText>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface Props {
toAddress: string
showHeader?: boolean
addressError: string
addressWarning: string
onSubmit: () => void
onSelectNetwork: (network: EthereumChain) => void
onSelectAccount: (account: UserAccountType) => void
Expand All @@ -50,6 +51,7 @@ function SendTab (props: Props) {
showHeader,
assetOptions,
addressError,
addressWarning,
onSubmit,
onSelectNetwork,
onSelectAccount,
Expand Down Expand Up @@ -115,6 +117,7 @@ function SendTab (props: Props) {
toAddressOrUrl={toAddressOrUrl}
toAddress={toAddress}
addressError={addressError}
addressWarning={addressWarning}
onChangeSendView={onChangeSendView}
onInputChange={onInputChange}
onSelectPresetAmount={onSelectPresetAmount}
Expand Down
4 changes: 4 additions & 0 deletions components/brave_wallet_ui/constants/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ export interface GetIsStrongPassswordReturnInfo {
result: boolean
}

export interface GetChecksumEthAddressReturnInfo {
checksumAddress: string
}

export interface RecoveryObject {
value: string
id: number
Expand Down
4 changes: 4 additions & 0 deletions components/brave_wallet_ui/page/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
findENSAddress,
findUnstoppableDomainAddress,
getBalance,
getChecksumEthAddress,
getERC20Allowance,
onConnectHardwareWallet,
isStrongPassword
Expand Down Expand Up @@ -172,10 +173,12 @@ function Container (props: Props) {
toAddressOrUrl,
toAddress,
addressError,
addressWarning,
selectedSendAsset
} = useSend(
findENSAddress,
findUnstoppableDomainAddress,
getChecksumEthAddress,
sendAssetOptions,
selectedAccount,
props.walletActions.sendERC20Transfer,
Expand Down Expand Up @@ -662,6 +665,7 @@ function Container (props: Props) {
fromAssetBalance={fromAssetBalance}
toAmount={toAmount}
addressError={addressError}
addressWarning={addressWarning}
toAssetBalance={toAssetBalance}
orderExpiration={orderExpiration}
slippageTolerance={slippageTolerance}
Expand Down
4 changes: 4 additions & 0 deletions components/brave_wallet_ui/panel/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import { GetNetworkInfo } from '../utils/network-utils'
import {
findENSAddress,
findUnstoppableDomainAddress,
getChecksumEthAddress,
getERC20Allowance
} from '../common/async/lib'
import { isHardwareAccount } from '../utils/address-utils'
Expand Down Expand Up @@ -182,10 +183,12 @@ function Container (props: Props) {
toAddressOrUrl,
toAddress,
addressError,
addressWarning,
selectedSendAsset
} = useSend(
findENSAddress,
findUnstoppableDomainAddress,
getChecksumEthAddress,
sendAssetOptions,
selectedAccount,
props.walletActions.sendERC20Transfer,
Expand Down Expand Up @@ -766,6 +769,7 @@ function Container (props: Props) {
selectedAssetAmount={sendAmount}
selectedAssetBalance={sendAssetBalance}
addressError={addressError}
addressWarning={addressWarning}
toAddressOrUrl={toAddressOrUrl}
toAddress={toAddress}
/>
Expand Down
2 changes: 2 additions & 0 deletions components/brave_wallet_ui/stories/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,8 @@ provideStrings({
braveWalletNotDomain: 'Domain is not registered',
braveWalletSameAddressError: 'The receiving address is your own address',
braveWalletContractAddressError: 'The receiving address is a tokens contract address',
braveWalletAddressMissingChecksumInfoWarning: 'Missing checksum information',
braveWalletNotValidChecksumAddressError: 'Invalid checksum information',

// Transaction Queue Strings
braveWalletQueueOf: 'of',
Expand Down
3 changes: 3 additions & 0 deletions components/brave_wallet_ui/stories/screens/buy-send-swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface Props {
toAddressOrUrl: string
toAddress: string
addressError: string
addressWarning: string
buyAssetOptions: AccountAssetOptionType[]
sendAssetOptions: AccountAssetOptionType[]
swapAssetOptions: AccountAssetOptionType[]
Expand Down Expand Up @@ -95,6 +96,7 @@ function BuySendSwap (props: Props) {
fromAmount,
toAmount,
addressError,
addressWarning,
selectedSendAsset,
sendAssetBalance,
fromAssetBalance,
Expand Down Expand Up @@ -213,6 +215,7 @@ function BuySendSwap (props: Props) {
{selectedTab === 'send' &&
<Send
addressError={addressError}
addressWarning={addressWarning}
accounts={accounts}
networkList={networkList}
selectedAssetAmount={sendAmount}
Expand Down
1 change: 1 addition & 0 deletions components/brave_wallet_ui/stories/wallet-concept.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ export const _DesktopWalletConcept = (args: { onboarding: boolean, locked: boole
toAddressOrUrl={toAddress}
toAddress={toAddress}
addressError=''
addressWarning=''
isFetchingSwapQuote={false}
isSwapSubmitDisabled={false}
customSlippageTolerance={customTolerance}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ export const _ConnectedPanel = (args: { locked: boolean }) => {
onSelectPresetAmount={onSelectPresetAmount}
onSubmit={onSubmitSend}
addressError=''
addressWarning=''
selectedAsset={selectedAsset}
selectedAssetAmount={fromAmount}
selectedAssetBalance={selectedAccount.balance.toString()}
Expand Down
2 changes: 2 additions & 0 deletions components/resources/wallet_strings.grdp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@
<message name="IDS_BRAVE_WALLET_NOT_DOMAIN" desc="Send input not registered domain error">Domain <ph name="DOMAIN_NAME"><ex>doug.wallet</ex>$1</ph> is not registered</message>
<message name="IDS_BRAVE_WALLET_SAME_ADDRESS_ERROR" desc="Send input trying to send crypto to their own address">The receiving address is your own address</message>
<message name="IDS_BRAVE_WALLET_CONTRACT_ADDRESS_ERROR" desc="Send input trying to send crypto to a tokens contract address">The receiving address is a token's contract address</message>
<message name="IDS_BRAVE_WALLET_ADDRESS_MISSING_CHECKSUM_INFO_WARNING" desc="Send input address missing checksum information">Missing checksum information</message>
<message name="IDS_BRAVE_WALLET_NOT_VALID_CHECKSUM_ADDRESS_ERROR" desc="Send input address has invalid checksum information">Invalid checksum information</message>
<message name="IDS_BRAVE_WALLET_QUEUE_OF" desc="Confirm Transaction Queue of">of</message>
<message name="IDS_BRAVE_WALLET_QUEUE_NEXT" desc="Confirm Transaction Queue next">next</message>
<message name="IDS_BRAVE_WALLET_QUEUE_FIRST" desc="Confirm Transaction Queue first">first</message>
Expand Down

0 comments on commit a40e050

Please sign in to comment.