Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wallet): add EIP-55 checksum address checks in Send widget #11607

Merged
merged 1 commit into from
Dec 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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