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

fix: address book undefined entry address #1338

Merged
merged 6 commits into from
Dec 19, 2022
Merged

Conversation

DiogoSoaress
Copy link
Member

What it solves

Resolves #1283

How this PR fixes it

Validates the address book in the selector

How to test it

I've added a unit test for it.
Alternatively, I was testing it locally by setting a faulty addressBookSlice initialSate.

const initialState: AddressBookState = {
  5: {
    '0x744aaf04ad770895ce469300771d2ca38463cfa0': 'legit',
    undefined: 'bug',
  },
}

@github-actions
Copy link

github-actions bot commented Dec 9, 2022

Branch preview

✅ Deploy successful!

https://fix_undefined_address_input--webcore.review-web-core.5afe.dev

@github-actions
Copy link

github-actions bot commented Dec 9, 2022

ESLint Summary View Full Report

Annotations are provided inline on the Files Changed tab. You can also see all annotations that were generated on the annotations page.

Type Occurrences Fixable
Errors 0 0
Warnings 0 0
Ignored 0 N/A
  • Result: ✅ success
  • Annotations: 0 total

Report generated by eslint-plus-action

Copy link
Member

@schmanu schmanu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we should even overwrite the addressBook with the valid entries instead of always filtering them out.
But as this should not exist outside of dev / QA Safes it's probably also not too important.

The validation is not checking for correct checksums though which is required for our address book entries.

@@ -45,6 +47,8 @@ export const selectAllAddressBooks = (state: RootState): AddressBookState => {
export const selectAddressBookByChain = createSelector(
[selectAllAddressBooks, (_, chainId: string) => chainId],
(allAddressBooks, chainId): AddressBook => {
return chainId ? allAddressBooks[chainId] || {} : {}
const chainAddresses = allAddressBooks[chainId]
const validAddresses = pickBy(chainAddresses, (_, key) => ADDRESS_RE.test(key))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a function to validate addresses. This additionally validates that addresses are checksummed, which we also expect in our addressbook.

Suggested change
const validAddresses = pickBy(chainAddresses, (_, key) => ADDRESS_RE.test(key))
const validAddresses = pickBy(chainAddresses, (_, key) => validateAddress(key) === undefined)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will not validate the address if it isn't checksummed. I didn't use it because it was filtering out the non-checksummed addresses

@@ -2,9 +2,8 @@ import chains from '@/config/chains'
import { parsePrefixedAddress, sameAddress, isChecksummedAddress } from './addresses'
import { safeFormatUnits, safeParseUnits } from './formatters'

export const ADDRESS_RE = /^0x[0-9a-f]{40}$/i
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move it back into validateAddress because that is the function which always should be used IMO.

If we need a helper that returns a boolean we should add something like

export const isValidAddress = (address: string) => {
   return validateAddress(address) === undefined
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we should probably split validateAddress function because it is doing two things at the moment:

  • validating the address format
  • validating if checksum

Initially I was using that function but it would filter out any address not checksummed and I think we don't want to go that strict in the AB, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need a helper that returns a boolean

I think we can use the validation as it is -> returning undefined if passed all checks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We checksum every address which gets added to the address book. And if its incorrectly checksummed it will not let you add that address. So I think we should go quite strict.
Some APIs only work with checksummed addresses including our tx service for instance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we validate them when added to the AB, and in address inputs, validating also in the selector seems like an overkill. And it's computationally not the fastest.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've included the checksum validation. Reason being an unchecksummed address might be introduced during a development stage, the same way the corrupted AB with an undefined entry was.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it's computationally not the fastest.

I didn't experience any degradation of performance but to be fair my AB is not extensively populated.

@@ -54,4 +60,17 @@ describe('addressBookSlice', () => {
'4': { '0x0': 'Charlie', '0x1': 'Dave' },
})
})

it('should not return entries with invalid address format', () => {
const initialState = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kudos for adding a test :)

src/utils/validation.ts Outdated Show resolved Hide resolved
Copy link
Member

@katspaugh katspaugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good!

Did you test in the UI with a bogus AB in LS?

@DiogoSoaress
Copy link
Member Author

The validation is not checking for correct checksums though which is required for our address book entries.

@schmanu so should the selector return only checksummed valid addresses?

@DiogoSoaress
Copy link
Member Author

Did you test in the UI with a bogus AB in LS?

Yes! I was able to reproduce the original error with the slice state I included in the PR description :) but added a unit test nevertheless

@DiogoSoaress DiogoSoaress requested a review from schmanu December 9, 2022 11:59
Comment on lines 5 to 8
export const validateAddress = (address: string) => {
const ADDRESS_RE = /^0x[0-9a-f]{40}$/i
const ADDRESS_RE = /^0x[0-9a-f]{40}$/i
export const isAddress = (address: string) => ADDRESS_RE.test(address)

if (!ADDRESS_RE.test(address)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore it how it was if it's not used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

@schmanu schmanu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good now! 🥳

@iamacook
Copy link
Member

iamacook commented Dec 19, 2022

Using the example initial state (which includes one valid address), the crash no longer happens. However, it does not return any entries in the address book or send asset modal. I think it should at least show the valid address? I tested this in Firefox and Chrome.

image

image

image

@schmanu
Copy link
Member

schmanu commented Dec 19, 2022

@iamacook I think the address from the example 0x744aaf04ad770895ce469300771d2ca38463cfa0 is not accepted because it is not checksummed. So I guess the example is not correct. Usually addresses should also always be checksummed in the addressbook.
If I checksum the address first to 0x744aAF04AD770895Ce469300771D2CA38463cFa0 it works.

@katspaugh katspaugh merged commit 07fc3b3 into dev Dec 19, 2022
@katspaugh katspaugh deleted the fix-undefined-address-input branch December 19, 2022 11:25
@gitpoap-bot
Copy link

gitpoap-bot bot commented Dec 19, 2022

Congrats, your important contribution to this open-source project has earned you a GitPOAP!

GitPOAP: 2022 Safe Web Core Contributor:

GitPOAP: 2022 Safe Web Core Contributor GitPOAP Badge

Head to gitpoap.io & connect your GitHub account to mint!

Learn more about GitPOAPs here.

@github-actions github-actions bot locked and limited conversation to collaborators Dec 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cant create tx on goerli
4 participants