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

Metamask address support #20844

Merged
merged 12 commits into from
Aug 29, 2024
Merged

Metamask address support #20844

merged 12 commits into from
Aug 29, 2024

Conversation

vkjr
Copy link
Contributor

@vkjr vkjr commented Jul 22, 2024

fixes #19986

Summary

This PR adds support for metamask addresses, they now can be scanned from QR codes and converted to Status addresses.
Small additional changes:

  • functions to manipulate addresses moved to utils.address namespace
  • few more meaningful renamings
  • tests added

Review notes

Metamask stores addresses in QR codes with the following format:
ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa

ethereum: - prefix described in ethereum/EIPs#67
0xa - chain ID suffix described in EIP-155

Testing notes

Bunch of qr codes for quick testing:

status-qr-multichain
status-qr-profile
metamask-qr-@0xa4b1
metamask-qr-@0xa
metamask-qr-@0x1

Platforms

  • Android
  • iOS

Areas that maybe impacted

@vkjr vkjr self-assigned this Jul 22, 2024
@vkjr vkjr changed the title Metamask address support [WIP] Metamask address support Jul 22, 2024
@status-im-auto
Copy link
Member

status-im-auto commented Jul 22, 2024

Jenkins Builds

Click to see older builds (43)
Commit #️⃣ Finished (UTC) Duration Platform Result
98b6322 #1 2024-07-22 13:25:36 ~3 min tests 📄log
✔️ 98b6322 #1 2024-07-22 13:31:17 ~8 min android-e2e 🤖apk 📲
✔️ 98b6322 #1 2024-07-22 13:31:26 ~8 min android 🤖apk 📲
✔️ 98b6322 #1 2024-07-22 13:34:37 ~12 min ios 📱ipa 📲
13d2ffb #2 2024-07-22 16:14:57 ~2 min tests 📄log
✔️ 13d2ffb #2 2024-07-22 16:18:39 ~6 min android-e2e 🤖apk 📲
✔️ 13d2ffb #2 2024-07-22 16:19:13 ~6 min android 🤖apk 📲
e9f4f81 #3 2024-07-22 16:23:53 ~2 min tests 📄log
✔️ e9f4f81 #3 2024-07-22 16:28:39 ~7 min android 🤖apk 📲
✔️ e9f4f81 #3 2024-07-22 16:29:03 ~7 min android-e2e 🤖apk 📲
✔️ e9f4f81 #3 2024-07-22 16:31:29 ~10 min ios 📱ipa 📲
704ed01 #4 2024-07-23 11:10:28 ~3 min tests 📄log
✔️ 704ed01 #4 2024-07-23 11:13:10 ~6 min android-e2e 🤖apk 📲
✔️ 704ed01 #4 2024-07-23 11:14:47 ~7 min android 🤖apk 📲
✔️ 704ed01 #4 2024-07-23 11:19:10 ~12 min ios 📱ipa 📲
89b769c #5 2024-07-23 11:38:29 ~2 min tests 📄log
✔️ 89b769c #5 2024-07-23 11:42:24 ~6 min android 🤖apk 📲
✔️ 89b769c #5 2024-07-23 11:43:23 ~7 min android-e2e 🤖apk 📲
✔️ 89b769c #5 2024-07-23 11:46:25 ~10 min ios 📱ipa 📲
✔️ 8a38102 #6 2024-07-24 13:13:27 ~4 min tests 📄log
✔️ 8a38102 #6 2024-07-24 13:16:53 ~8 min android 🤖apk 📲
✔️ 8a38102 #6 2024-07-24 13:17:03 ~8 min android-e2e 🤖apk 📲
✔️ 8a38102 #6 2024-07-24 13:20:34 ~12 min ios 📱ipa 📲
✔️ fb352d7 #7 2024-07-30 15:30:29 ~4 min tests 📄log
✔️ fb352d7 #7 2024-07-30 15:32:25 ~6 min android-e2e 🤖apk 📲
✔️ fb352d7 #7 2024-07-30 15:32:51 ~7 min android 🤖apk 📲
✔️ fb352d7 #7 2024-07-30 15:39:28 ~13 min ios 📱ipa 📲
92cb0bf #8 2024-07-30 16:20:26 ~2 min tests 📄log
✔️ 92cb0bf #8 2024-07-30 16:24:46 ~6 min android 🤖apk 📲
✔️ 92cb0bf #8 2024-07-30 16:24:57 ~7 min android-e2e 🤖apk 📲
✔️ 92cb0bf #8 2024-07-30 16:34:14 ~16 min ios 📱ipa 📲
1e6b0f1 #9 2024-08-23 12:48:20 ~3 min tests 📄log
✔️ 1e6b0f1 #9 2024-08-23 12:53:26 ~8 min android-e2e 🤖apk 📲
✔️ 1e6b0f1 #9 2024-08-23 12:53:34 ~8 min android 🤖apk 📲
✔️ 1e6b0f1 #9 2024-08-23 12:55:11 ~10 min ios 📱ipa 📲
4250ada #10 2024-08-26 13:52:10 ~2 min tests 📄log
✔️ 4250ada #10 2024-08-26 13:56:42 ~7 min android-e2e 🤖apk 📲
✔️ 4250ada #10 2024-08-26 13:59:06 ~9 min android 🤖apk 📲
✔️ 4250ada #10 2024-08-26 13:59:48 ~10 min ios 📱ipa 📲
✔️ 79c5965 #11 2024-08-28 13:28:52 ~5 min tests 📄log
✔️ 79c5965 #11 2024-08-28 13:31:04 ~7 min android-e2e 🤖apk 📲
✔️ 79c5965 #11 2024-08-28 13:31:45 ~8 min android 🤖apk 📲
✔️ 79c5965 #11 2024-08-28 13:59:31 ~35 min ios 📱ipa 📲
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ b755811 #12 2024-08-29 11:22:36 ~4 min tests 📄log
✔️ b755811 #12 2024-08-29 11:25:11 ~7 min android 🤖apk 📲
✔️ b755811 #12 2024-08-29 11:25:36 ~7 min android-e2e 🤖apk 📲
✔️ b755811 #12 2024-08-29 11:29:44 ~11 min ios 📱ipa 📲
✔️ 9fb3255 #13 2024-08-29 11:41:14 ~4 min tests 📄log
✔️ 9fb3255 #13 2024-08-29 11:43:34 ~6 min android-e2e 🤖apk 📲
✔️ 9fb3255 #13 2024-08-29 11:45:28 ~8 min android 🤖apk 📲
✔️ 9fb3255 #13 2024-08-29 11:47:37 ~10 min ios 📱ipa 📲

@vkjr vkjr marked this pull request as ready for review July 23, 2024 11:42
@J-Son89
Copy link
Contributor

J-Son89 commented Jul 23, 2024

It's WIP or not? 🤔

@vkjr vkjr changed the title [WIP] Metamask address support Metamask address support Jul 24, 2024
@vkjr
Copy link
Contributor Author

vkjr commented Jul 24, 2024

@J-Son89, not anymore)

Copy link
Contributor

@ulisesmac ulisesmac left a comment

Choose a reason for hiding this comment

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

Hi @vkjr

Thanks for your PR!
I left a some comments

Comment on lines 22 to 24
(defn- is-text-a-status-url-for-path?
[text path]
(some #(string/starts-with? text %) (router/path-urls path)))
(some #(string/starts-with? text %) (router/prepend-status-urls path)))
Copy link
Contributor

Choose a reason for hiding this comment

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

Booleans in Clojure don't start with the prefix is-, it's enough if we just provide the question mark at the end

(validation/eth-address? address) [:wallet/address-validation-success address]
:else [:wallet/address-validation-failed address])
(<= (count address) 0) [:wallet/address-validation-failed address]
(utils-address/eip-3770-address? address) [:wallet/address-validation-success address]
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Comment on lines 9 to 12
;; EIP-3770 is a format used by Status and described here: https://eips.ethereum.org/EIPS/eip-3770
(def regx-eip-3770-address #"^(?:(?:eth:|arb1:|oeth:)(?=:|))*0x[0-9a-fA-F]{40}$")
(def regx-metamask-address #"^ethereum:(0x[0-9a-fA-F]{40})@(0x1|0xa|0xa4b1)$")
(def regx-address-contains #"(?i)0x[a-fA-F0-9]{40}")
Copy link
Contributor

Choose a reason for hiding this comment

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

💯

"0xa" "oeth:"
nil))

(defn is-metamask-address?
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider what I mentioned before about the is- prefix in Clojure

Comment on lines 103 to 116
(defn metamask-address->status-address
[metamask-address]
(when-let [[_ address metamask-network-suffix] (is-metamask-address? metamask-address)]
(when-let [status-network-prefix (eip-155-suffix->eip-3770-prefix metamask-network-suffix)]
(str status-network-prefix address))))
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO the usage of is-metamaks-address? isn't a good practice for future maintenance.

I understand that is-metamaks-address? will return the result of re-find, which is a vector of the matching regex groups, but since this function ends with ? it's better to always treat it as if its return value is a boolean.

What I'd suggest is to create a function that performs the string splitting you are performing with re-find and another function to just check if an address is a metamask one or not.

wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ulisesmac, I fully agree with you, the naming doesn't match current usecase and it is better to split function.
And with all other comments too, thanks a lot for reviewing!

Comment on lines 118 to 119
:else
nil))
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need :else nil for cond since it already returns nil when there isn't a matching clause.

Comment on lines 42 to 88

(def valid-metamask-addresses
["ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0x1"
"ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa4b1"
"ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa"])

(def invalid-metamask-addresses
["ethe:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0x1"
":0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa4b1"
"0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa"
"ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0x1d"
"ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd20xa4b1"
"ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2:0xa"
"ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2"])

(def metamask-to-status
[{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0x1"
:status "eth:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2"}
{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa4b1"
:status "arb1:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2"}
{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa"
:status "oeth:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2"}
{:metamask "ethe:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0x1" :status nil}
{:metamask ":0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa4b1" :status nil}
{:metamask "0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0xa" :status nil}
{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2@0x1d" :status nil}
{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd20xa4b1" :status nil}
{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2:0xa" :status nil}
{:metamask "ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2" :status nil}])

(deftest is-metamask-address?-test
(testing "Check valid metamask addresses"
(dorun
(for [address valid-metamask-addresses]
(is (utils.address/is-metamask-address? address)))))
(testing "Check invalid metamask addresses"
(dorun
(for [address invalid-metamask-addresses]
(is (not (utils.address/is-metamask-address? address)))))))

(deftest metamask-address->status-address-test
(testing "Check metamask to status address conversion is valid"
(dorun
(for [{metamask-address :metamask
status-address :status} metamask-to-status]
(is (= status-address (utils.address/metamask-address->status-address metamask-address)))))))
Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you for these tests! 👍 💯

@status-im-auto
Copy link
Member

57% of end-end tests have passed

Total executed tests: 7
Failed tests: 3
Expected to fail tests: 0
Passed tests: 4
IDs of failed tests: 727230,702843,727229 

Failed tests (3)

Click to expand
  • Rerun failed tests

  • Class TestCommunityMultipleDeviceMerged:

    1. test_community_message_edit, id: 702843

    Device 2: Looking for a message by text: Message AFTER edit 2 (Edited)
    Device 2: Find `ChatElementByText` by `xpath`: `//*[starts-with(@text,'Message AFTER edit 2 (Edited)')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']`

    critical/chats/test_public_chat_browsing.py:378: in test_community_message_edit
        self.channel_2.set_reaction(message_text_after_edit)
    ../views/chat_view.py:1053: in set_reaction
        self.chat_element_by_text(message).long_press_until_element_is_shown(element)
    ../views/base_element.py:327: in long_press_until_element_is_shown
        element = self.find_element()
    ../views/chat_view.py:116: in find_element
        self.wait_for_visibility_of_element(20)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: ChatElementByText by xpath:`//*[starts-with(@text,'Message AFTER edit 2 (Edited)')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']` is not found on the screen after wait_for_visibility_of_element
    



    Device sessions

    Class TestWalletMultipleDevice:

    1. test_wallet_send_asset_from_drawer, id: 727230

    Device 2: Find Text by xpath: //android.view.ViewGroup[@content-desc='container']/android.widget.TextView[@text='Ether']/../android.widget.TextView[3]
    Device 2: Text is 0.03939 ETH

    critical/test_wallet.py:190: in test_wallet_send_asset_from_drawer
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Sender balance is not updated on Etherscan, it is 0.452 but expected to be 0.4521
    



    2. test_wallet_send_eth, id: 727229

    Device 2: Find Text by xpath: //android.view.ViewGroup[@content-desc='container']/android.widget.TextView[@text='Ether']/../android.widget.TextView[3]
    Device 2: Text is 0.03929 ETH

    critical/test_wallet.py:159: in test_wallet_send_eth
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Sender balance is not updated on Etherscan, it is 0.4522 but expected to be 0.4523
    



    Passed tests (4)

    Click to expand

    Class TestWalletOneDevice:

    1. test_wallet_add_remove_regular_account, id: 727231
    Device sessions

    Class TestOneToOneChatMultipleSharedDevicesNewUi:

    1. test_1_1_chat_non_latin_messages_stack_update_profile_photo, id: 702745
    Device sessions

    Class TestCommunityOneDeviceMerged:

    1. test_community_copy_and_paste_message_in_chat_input, id: 702742
    Device sessions

    2. test_restore_multiaccount_with_waku_backup_remove_switch, id: 703133
    Device sessions

    @VolodLytvynenko
    Copy link
    Contributor

    VolodLytvynenko commented Aug 28, 2024

    @vkjr Thank you for the PR. Here are found issues:

    ISSUE 1: User navigated to overview wallet page when MetaMask QR is Scanned by Universal Scanner

    Steps:

    1. Open the universal scanner on the app.
    2. Scan a MetaMask QR code (QR that contains "ethereum:" prefix)
      image

    Actual Result:

    The user is navigated to the wallet overview page after scanning the MetaMask QR code.

    wallet.mp4

    Expected Result:

    The app should recognize the MetaMask QR code and show the drawer with the scanned address.
    After converting, ethereum:0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2 should become 0x38cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2

    image

    Devices:

    Pixel 7a, Android 13
    iPhone 11 Pro Max, iOS 17

    Additional info:

    The QR with "ethereum" prefix is not recognized on the Send to page as well "Oops this is not QR" toast is shown

    qr_scanning.mp4

    @vkjr
    Copy link
    Contributor Author

    vkjr commented Aug 28, 2024

    @VolodLytvynenko , thanks for finding, checking!

    @VolodLytvynenko
    Copy link
    Contributor

    Hi @vkjr, the PR looks great. The QR code issue mentioned in this comment seems to be related to the Metamask plugin. The mobile version usually shares other QRs, which can be scanned well using a build of this PR. The issue can be fixed in a follow-up, but if you think it’s better to address it in this PR, feel free to do so. Otherwise, PR can be merged

    @vkjr
    Copy link
    Contributor Author

    vkjr commented Aug 28, 2024

    @VolodLytvynenko, qr code from metamask plugin contains text ethereum:0xFC6327a092f6232e158a0Dd1d6d967a2e1c65cD5 and it has no suffix, so it is not strictly follow the rules that described in original issue . But I think that we can simply imply that addresses without suffix are belong to mainnet, wdyt? Also @xAlisher, wdyt?

    @VolodLytvynenko
    Copy link
    Contributor

    @VolodLytvynenko, qr code from metamask plugin contains text ethereum:0xFC6327a092f6232e158a0Dd1d6d967a2e1c65cD5 and it has no suffix, so it is not strictly follow the rules that described in original issue . But I think that we can simply imply that addresses without suffix are belong to mainnet, wdyt? Also @xAlisher, wdyt?

    @vkjr The best way to address this issue is to ignore the "ethereum:" prefix and only extract the address body, like 0xFC6327a092f6232e158a0Dd1d6d967a2e1c65cD5. In MetaMask, the "ethereum:" prefix doesn’t necessarily indicate the mainnet—it appears even when other networks are selected.

    @vkjr
    Copy link
    Contributor Author

    vkjr commented Aug 29, 2024

    @VolodLytvynenko, I added support to ethereum addresses without suffixes. Could you please briefly take a look, just to make sure all is good?

    @status-im-auto
    Copy link
    Member

    71% of end-end tests have passed

    Total executed tests: 7
    Failed tests: 2
    Expected to fail tests: 0
    Passed tests: 5
    
    IDs of failed tests: 727230,727229 
    

    Failed tests (2)

    Click to expand
  • Rerun failed tests

  • Class TestWalletMultipleDevice:

    1. test_wallet_send_asset_from_drawer, id: 727230

    Device 2: Find `Text` by `xpath`: `//android.view.ViewGroup[@content-desc='container']/android.widget.TextView[@text='Ether']/../android.widget.TextView[3]`
    Device 2: `Text` is `0.04199 ETH`

    critical/test_wallet.py:190: in test_wallet_send_asset_from_drawer
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Sender balance is not updated on Etherscan, it is 0.4479 but expected to be 0.448
    



    2. test_wallet_send_eth, id: 727229

    Device 2: Find Text by xpath: //android.view.ViewGroup[@content-desc='container']/android.widget.TextView[@text='Ether']/../android.widget.TextView[3]
    Device 2: Text is 0.04189 ETH

    critical/test_wallet.py:159: in test_wallet_send_eth
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Sender balance is not updated on Etherscan, it is 0.4481 but expected to be 0.4482
    



    Passed tests (5)

    Click to expand

    Class TestCommunityOneDeviceMerged:

    1. test_community_copy_and_paste_message_in_chat_input, id: 702742
    Device sessions

    2. test_restore_multiaccount_with_waku_backup_remove_switch, id: 703133
    Device sessions

    Class TestWalletOneDevice:

    1. test_wallet_add_remove_regular_account, id: 727231
    Device sessions

    Class TestOneToOneChatMultipleSharedDevicesNewUi:

    1. test_1_1_chat_non_latin_messages_stack_update_profile_photo, id: 702745
    Device sessions

    Class TestCommunityMultipleDeviceMerged:

    1. test_community_message_edit, id: 702843
    Device sessions

    @vkjr
    Copy link
    Contributor Author

    vkjr commented Aug 29, 2024

    @VolodLytvynenko, are the results of endtoend testing acceptable?

    @VolodLytvynenko
    Copy link
    Contributor

    @VolodLytvynenko, are the results of endtoend testing acceptable?

    @vkjr Yes. e2e are ok. PR can be merged. Thank you!

    @vkjr
    Copy link
    Contributor Author

    vkjr commented Aug 29, 2024

    @VolodLytvynenko, thank you!

    @vkjr vkjr merged commit bf7b86c into develop Aug 29, 2024
    5 checks passed
    @vkjr vkjr deleted the metamask-address branch August 29, 2024 14:48
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    Archived in project
    Development

    Successfully merging this pull request may close these issues.

    Support Metamask address QRs
    5 participants