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

Add ENS name resolution for EIP681 URIs and support in QR code scanner #9240

Closed
wants to merge 6 commits into from
Closed
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
33 changes: 24 additions & 9 deletions src/status_im/ethereum/eip681.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

e.g. ethereum:0x1234@1/transfer?to=0x5678&value=1e18&gas=5000"
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.tokens :as tokens]
[status-im.utils.money :as money]))

Expand Down Expand Up @@ -41,21 +43,34 @@
{:function-arguments (apply dissoc m valid-native-arguments)}))
arguments)))

;; TODO add ENS support

(defn parse-uri
"Parse a EIP 681 URI as a map (keyword / strings). Parsed map will contain at least the key `address`.
Note that values are not decoded and you might need to rely on specific methods for some fields (parse-value, parse-number).
"Parse a EIP 681 URI as a map (keyword / strings). Parsed map will contain at least the key `address`
which will be either a valid ENS or Ethereum address.
Note that values are not decoded and you might need to rely on specific methods for some fields
(parse-value, parse-number).
Invalid URI will be parsed as `nil`."
[s]
(when (string? s)
(let [[_ authority-path query] (re-find uri-pattern s)]
(when authority-path
(let [[_ address chain-id function-name] (re-find authority-path-pattern authority-path)]
(when (ethereum/address? address)
(when-let [arguments (parse-arguments function-name query)]
(merge {:address address :chain-id (if chain-id (js/parseInt chain-id) (ethereum/chain-keyword->chain-id :mainnet))}
arguments))))))))
(let [[_ raw-address chain-id function-name] (re-find authority-path-pattern authority-path)]
(when (or (ethereum/address? raw-address)
(if (string/starts-with? raw-address "pay-")
(let [pay-address (string/replace-first raw-address "pay-" "")]
(or (ens/is-valid-eth-name? pay-address)
(ethereum/address? pay-address)))))
(let [address (if (string/starts-with? raw-address "pay-")
(string/replace-first raw-address "pay-" "")
raw-address)]
(when-let [arguments (parse-arguments function-name query)]
3esmit marked this conversation as resolved.
Show resolved Hide resolved
(let [contract-address (get-in arguments [:function-arguments :address])]
(if-not (or (not contract-address) (or (ens/is-valid-eth-name? contract-address) (ethereum/address? contract-address)))
nil
(merge {:address address
:chain-id (if chain-id
(js/parseInt chain-id)
(ethereum/chain-keyword->chain-id :mainnet))}
arguments)))))))))))

(defn parse-eth-value [s]
"Takes a map as returned by `parse-uri` and returns value as BigNumber"
Expand Down
72 changes: 72 additions & 0 deletions src/status_im/ui/screens/wallet/choose_recipient/views.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
(ns status-im.ui.screens.wallet.choose-recipient.views
Copy link
Contributor

Choose a reason for hiding this comment

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

this view doesn't exist anymore in develop

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense now that I look at it again. I'll try it again later today.

(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.camera :as camera]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.view :as topbar]
[status-im.ui.screens.wallet.choose-recipient.styles :as styles]
[status-im.utils.platform :as platform]
[status-im.ethereum.eip681 :as eip681]))

(defn- topbar [camera-flashlight]
[topbar/toolbar
{:transparent? true}
[topbar/nav-button (actions/back-white actions/default-handler)]
[topbar/content-title {:color :white}
(i18n/label :t/wallet-choose-recipient)]
[topbar/actions [{:icon (if (= :on camera-flashlight)
:main-icons/flash-active
:main-icons/flash-inactive)
:icon-opts {:color :white}
:handler #(re-frame/dispatch [:wallet/toggle-flashlight])}]]])

(defn- viewfinder [{:keys [height width]} size]
(let [height (cond-> height
platform/iphone-x? (- 78))]
[react/view {:style styles/viewfinder-port}
[react/view {:style (styles/viewfinder-translucent height width size :top)}]
[react/view {:style (styles/viewfinder-translucent height width size :right)}]
[react/view {:style (styles/viewfinder-translucent height width size :bottom)}]
[react/view {:style (styles/viewfinder-translucent height width size :left)}]
[react/image {:source {:uri :corner_left_top}
:style (styles/corner-left-top height width size)}]
[react/image {:source {:uri :corner_right_top}
:style (styles/corner-right-top height width size)}]
[react/image {:source {:uri :corner_left_bottom}
:style (styles/corner-left-bottom height width size)}]
[react/image {:source {:uri :corner_right_bottom}
:style (styles/corner-right-bottom height width size)}]]))

(defn- size [{:keys [height width]}]
(int (* 2 (/ (min height width) 3))))

(defview choose-recipient []
(letsubs [read-once? (atom false)
dimensions [:dimensions/window]
camera-flashlight [:wallet.send/camera-flashlight]]
[react/view {:style styles/qr-code}
[status-bar/status-bar {:type :transparent}]
[topbar camera-flashlight]
[react/text {:style (styles/qr-code-text dimensions)
:accessibility-label :scan-qr-code-with-wallet-address-text}
(i18n/label :t/scan-qr-code)]
[react/view {:style styles/qr-container
:pointer-events :none}
[react/with-activity-indicator
{}
[camera/camera {:style styles/preview
;:torchMode (camera/set-torch camera-flashlight)
:onBarCodeRead #(when-not @read-once?
(reset! read-once? true)
(re-frame/dispatch [:wallet.send/resolve-ens-addresses (camera/get-qr-code-data %) :qr]))}]]
acolytec3 marked this conversation as resolved.
Show resolved Hide resolved
[viewfinder dimensions (size dimensions)]]
[toolbar/toolbar
{:center {:type :secondary
:disabled? false
:on-press #(re-frame/dispatch [:navigate-back])
:accessibility-label :cancel-button
:label :t/cancel}}]]))
Loading