[BUG #2029] Properly handle gas details from payment requests
This commit is contained in:
parent
0a1c3bcd88
commit
f90e1a4ed3
|
@ -3,7 +3,8 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.utils.ethereum.core :as ethereum]
|
[status-im.utils.ethereum.core :as ethereum]
|
||||||
[status-im.utils.ethereum.eip681 :as eip681]
|
[status-im.utils.ethereum.eip681 :as eip681]
|
||||||
[status-im.utils.handlers :as handlers]))
|
[status-im.utils.handlers :as handlers]
|
||||||
|
[status-im.utils.money :as money]))
|
||||||
|
|
||||||
(handlers/register-handler-db
|
(handlers/register-handler-db
|
||||||
:wallet/toggle-flashlight
|
:wallet/toggle-flashlight
|
||||||
|
@ -12,37 +13,44 @@
|
||||||
toggled-state (if (= :on flashlight-state) :off :on)]
|
toggled-state (if (= :on flashlight-state) :off :on)]
|
||||||
(assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state))))
|
(assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state))))
|
||||||
|
|
||||||
(defn- fill-request-details [db address name amount]
|
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice] :as m}]
|
||||||
|
{:pre [(not (nil? address))]}
|
||||||
(update-in
|
(update-in
|
||||||
db [:wallet :send-transaction]
|
db [:wallet :send-transaction]
|
||||||
#(cond-> (assoc % :to address :to-name name)
|
#(cond-> (assoc % :to address)
|
||||||
amount (assoc :amount amount))))
|
value (assoc :amount value)
|
||||||
|
name (assoc :to-name name)
|
||||||
|
symbol (assoc :symbol symbol)
|
||||||
|
gas (assoc :gas (money/bignumber gas))
|
||||||
|
gasPrice (assoc :gas-price (money/bignumber gasPrice))
|
||||||
|
(and symbol (not gasPrice))
|
||||||
|
(assoc :gas-price (ethereum/estimate-gas symbol)))))
|
||||||
|
|
||||||
(defn- extract-details
|
(defn- extract-details
|
||||||
"First try to parse as EIP681 URI, if not assume this is an address directly.
|
"First try to parse as EIP681 URI, if not assume this is an address directly.
|
||||||
Returns a map containing at least the `address`, `symbol` and `chain-id` keys"
|
Returns a map containing at least the `address` and `chain-id` keys"
|
||||||
[s chain-id]
|
[s chain-id]
|
||||||
(or (let [m (eip681/parse-uri s)]
|
(or (let [m (eip681/parse-uri s)]
|
||||||
(merge m (eip681/extract-request-details m)))
|
(merge m (eip681/extract-request-details m)))
|
||||||
(when (ethereum/address? s)
|
(when (ethereum/address? s)
|
||||||
{:address s :chain-id chain-id :symbol :ETH})))
|
{:address s :chain-id chain-id})))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet/fill-request-from-url
|
:wallet/fill-request-from-url
|
||||||
(fn [{{:keys [web3 network] :as db} :db} [_ data name]]
|
(fn [{{:keys [web3 network] :as db} :db} [_ data name]]
|
||||||
(let [{:keys [view-id]} db
|
(let [{:keys [view-id]} db
|
||||||
current-chain-id (get-in constants/default-networks [network :raw-config :NetworkId])
|
current-chain-id (get-in constants/default-networks [network :raw-config :NetworkId])
|
||||||
{:keys [address chain-id value]} (extract-details data current-chain-id)
|
{:keys [address chain-id] :as details} (extract-details data current-chain-id)
|
||||||
valid-network? (boolean (= current-chain-id chain-id))]
|
valid-network? (boolean (= current-chain-id chain-id))]
|
||||||
(cond-> {:db db}
|
(cond-> {:db db}
|
||||||
(and address (= :choose-recipient view-id)) (assoc :dispatch [:navigate-back])
|
(and address (= :choose-recipient view-id)) (assoc :dispatch [:navigate-back])
|
||||||
(and address valid-network?) (update :db #(fill-request-details % address name value))
|
(and address valid-network?) (update :db #(fill-request-details % details))
|
||||||
(not address) (assoc :show-error (i18n/label :t/wallet-invalid-address {:data data}))
|
(not address) (assoc :show-error (i18n/label :t/wallet-invalid-address {:data data}))
|
||||||
(and address (not valid-network?)) (assoc :show-error (i18n/label :t/wallet-invalid-chain-id {:data data :chain current-chain-id}))))))
|
(and address (not valid-network?)) (assoc :show-error (i18n/label :t/wallet-invalid-chain-id {:data data :chain current-chain-id}))))))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet/fill-request-from-contact
|
:wallet/fill-request-from-contact
|
||||||
(fn [{db :db} [_ {:keys [address name]}]]
|
(fn [{db :db} [_ {:keys [address name]}]]
|
||||||
{:db (fill-request-details db address name nil)
|
{:db (fill-request-details db {:address address :name name})
|
||||||
:dispatch-n [[:navigate-back]
|
:dispatch-n [[:navigate-back]
|
||||||
[:navigate-back]]}))
|
[:navigate-back]]}))
|
||||||
|
|
|
@ -62,17 +62,16 @@
|
||||||
[react/text
|
[react/text
|
||||||
(name symbol)]]]))
|
(name symbol)]]]))
|
||||||
|
|
||||||
(views/defview choose-currency [style]
|
(views/defview choose-currency [{:keys [style on-change value]}]
|
||||||
(views/letsubs [visible-tokens [:wallet.settings/visible-tokens]
|
(views/letsubs [visible-tokens [:wallet.settings/visible-tokens]]
|
||||||
symbol [:wallet.send/symbol]]
|
|
||||||
[react/view
|
[react/view
|
||||||
[react/text {:style styles/label} (i18n/label :t/currency)]
|
[react/text {:style styles/label} (i18n/label :t/currency)]
|
||||||
[react/view (merge styles/currency-container
|
[react/view (merge styles/currency-container
|
||||||
style)
|
style)
|
||||||
[react/picker {:selected (name symbol)
|
[react/picker {:selected value
|
||||||
:style {:color "white"}
|
:style {:color "white"}
|
||||||
:item-style styles/wallet-name
|
:item-style styles/wallet-name
|
||||||
:on-change #(re-frame/dispatch [:wallet.send/set-symbol (keyword %)])}
|
:on-change on-change}
|
||||||
(map (fn [s] {:value (name s) :color "white"}) (conj visible-tokens (:symbol tokens/ethereum)))]]]))
|
(map (fn [s] {:value (name s) :color "white"}) (conj visible-tokens (:symbol tokens/ethereum)))]]]))
|
||||||
|
|
||||||
(defn choose-recipient-content [{:keys [address name on-press style]}]
|
(defn choose-recipient-content [{:keys [address name on-press style]}]
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
(spec/def ::amount (spec/nilable money/valid?))
|
(spec/def ::amount (spec/nilable money/valid?))
|
||||||
(spec/def ::amount-error (spec/nilable string?))
|
(spec/def ::amount-error (spec/nilable string?))
|
||||||
|
(spec/def ::symbol (spec/nilable keyword?))
|
||||||
|
|
||||||
(spec/def :wallet/request-transaction (allowed-keys
|
(spec/def :wallet/request-transaction (allowed-keys
|
||||||
:opt-un [::amount ::amount-error]))
|
:opt-un [::amount ::amount-error ::symbol]))
|
|
@ -32,3 +32,8 @@
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:wallet/request-transaction :amount] (money/ether->wei value))
|
(assoc-in [:wallet/request-transaction :amount] (money/ether->wei value))
|
||||||
(assoc-in [:wallet/request-transaction :amount-error] error))})))
|
(assoc-in [:wallet/request-transaction :amount-error] error))})))
|
||||||
|
|
||||||
|
(handlers/register-handler-fx
|
||||||
|
:wallet.request/set-symbol
|
||||||
|
(fn [{:keys [db]} [_ s]]
|
||||||
|
{:db (assoc-in db [:wallet/request-transaction :symbol] s)}))
|
|
@ -1,11 +1,14 @@
|
||||||
(ns status-im.ui.screens.wallet.request.subs
|
(ns status-im.ui.screens.wallet.request.subs
|
||||||
(:require [re-frame.core :as re-frame]))
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.utils.ethereum.tokens :as tokens]))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:wallet.request/request-enabled?
|
:wallet.request/request-enabled?
|
||||||
:<- [:get-in [:wallet/request-transaction :amount]]
|
:<- [:get-in [:wallet/request-transaction :amount]]
|
||||||
:<- [:get-in [:wallet/request-transaction :amount-error]]
|
:<- [:get-in [:wallet/request-transaction :amount-error]]
|
||||||
(fn [[amount amount-error]]
|
:<- [:get-in [:wallet/request-transaction :symbol]]
|
||||||
|
(fn [[amount amount-error symbol]]
|
||||||
(and
|
(and
|
||||||
|
(or (nil? symbol) (tokens/ethereum? symbol))
|
||||||
(nil? amount-error)
|
(nil? amount-error)
|
||||||
(not (nil? amount)))))
|
(not (nil? amount)))))
|
|
@ -1,7 +1,6 @@
|
||||||
(ns status-im.ui.screens.wallet.request.views
|
(ns status-im.ui.screens.wallet.request.views
|
||||||
(:require-macros [status-im.utils.views :as views])
|
(:require-macros [status-im.utils.views :as views])
|
||||||
(:require
|
(:require [re-frame.core :as re-frame]
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.qr-code :as components.qr-code]
|
[status-im.ui.components.qr-code :as components.qr-code]
|
||||||
[status-im.ui.components.toolbar.actions :as actions]
|
[status-im.ui.components.toolbar.actions :as actions]
|
||||||
|
@ -17,6 +16,7 @@
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.ethereum.core :as ethereum]
|
[status-im.utils.ethereum.core :as ethereum]
|
||||||
[status-im.utils.ethereum.eip681 :as eip681]
|
[status-im.utils.ethereum.eip681 :as eip681]
|
||||||
|
[status-im.utils.ethereum.tokens :as tokens]
|
||||||
[status-im.utils.money :as money]))
|
[status-im.utils.money :as money]))
|
||||||
|
|
||||||
(defn toolbar-view []
|
(defn toolbar-view []
|
||||||
|
@ -31,17 +31,25 @@
|
||||||
:action :request
|
:action :request
|
||||||
:params {:hide-actions? true}}]))
|
:params {:hide-actions? true}}]))
|
||||||
|
|
||||||
(views/defview qr-code [amount]
|
(defn- generate-value [address {:keys [symbol chain-id] :as m}]
|
||||||
|
(if (tokens/ethereum? symbol)
|
||||||
|
(eip681/generate-uri address (dissoc m :symbol))
|
||||||
|
(eip681/generate-erc20-uri address m)))
|
||||||
|
|
||||||
|
(views/defview qr-code [amount symbol]
|
||||||
(views/letsubs [account [:get-current-account]
|
(views/letsubs [account [:get-current-account]
|
||||||
chain-id [:get-network-id]]
|
chain-id [:get-network-id]]
|
||||||
[components.qr-code/qr-code
|
[components.qr-code/qr-code
|
||||||
{:value (eip681/generate-uri (ethereum/normalized-address (:address account)) (merge {:chain-id chain-id} (when amount {:value amount})))
|
(let [address (ethereum/normalized-address (:address account))
|
||||||
:size 256}]))
|
params {:chain-id chain-id :value amount :symbol (or symbol :ETH)}]
|
||||||
|
{:value (generate-value address params)
|
||||||
|
:size 256})]))
|
||||||
|
|
||||||
(views/defview request-transaction []
|
(views/defview request-transaction []
|
||||||
;;Because input field is in the end of view we will scroll to the end on input focus event
|
;;Because input field is in the end of view we will scroll to the end on input focus event
|
||||||
(views/letsubs [amount [:get-in [:wallet/request-transaction :amount]]
|
(views/letsubs [amount [:get-in [:wallet/request-transaction :amount]]
|
||||||
amount-error [:get-in [:wallet/request-transaction :amount-error]]
|
amount-error [:get-in [:wallet/request-transaction :amount-error]]
|
||||||
|
symbol [:get-in [:wallet/request-transaction :symbol]]
|
||||||
request-enabled? [:wallet.request/request-enabled?]
|
request-enabled? [:wallet.request/request-enabled?]
|
||||||
scroll (atom nil)]
|
scroll (atom nil)]
|
||||||
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
||||||
|
@ -52,7 +60,7 @@
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
[react/view styles/network-container
|
[react/view styles/network-container
|
||||||
[react/view styles/qr-container
|
[react/view styles/qr-container
|
||||||
[qr-code amount]]]
|
[qr-code amount symbol]]]
|
||||||
[react/view wallet.styles/choose-wallet-container
|
[react/view wallet.styles/choose-wallet-container
|
||||||
[components/choose-wallet]]
|
[components/choose-wallet]]
|
||||||
[react/view wallet.styles/amount-container
|
[react/view wallet.styles/amount-container
|
||||||
|
@ -61,7 +69,9 @@
|
||||||
:input-options {:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100)))
|
:input-options {:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100)))
|
||||||
:on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount %])}}]
|
:on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount %])}}]
|
||||||
[react/view wallet.styles/choose-currency-container
|
[react/view wallet.styles/choose-currency-container
|
||||||
[components/choose-currency wallet.styles/choose-currency]]]]]
|
[components/choose-currency {:style wallet.styles/choose-currency
|
||||||
|
:on-change #(re-frame/dispatch [:wallet.request/set-symbol (keyword %)])
|
||||||
|
:value (name (or symbol :ETH))}]]]]]
|
||||||
[components/separator]
|
[components/separator]
|
||||||
[react/view wallet.styles/buttons-container
|
[react/view wallet.styles/buttons-container
|
||||||
[react/touchable-highlight {:style wallet.styles/button :disabled true}
|
[react/touchable-highlight {:style wallet.styles/button :disabled true}
|
||||||
|
|
|
@ -70,17 +70,11 @@
|
||||||
(assoc-in [:wallet :send-transaction :amount] (money/ether->wei value))
|
(assoc-in [:wallet :send-transaction :amount] (money/ether->wei value))
|
||||||
(assoc-in [:wallet :send-transaction :amount-error] error))})))
|
(assoc-in [:wallet :send-transaction :amount-error] error))})))
|
||||||
|
|
||||||
(defn- estimated-gas [symbol]
|
|
||||||
(if (tokens/ethereum? symbol)
|
|
||||||
ethereum/default-transaction-gas
|
|
||||||
;; TODO(jeluard) Rely on estimateGas call
|
|
||||||
(.times ethereum/default-transaction-gas 5)))
|
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet.send/set-symbol
|
:wallet.send/set-symbol
|
||||||
(fn [{:keys [db]} [_ symbol]]
|
(fn [{:keys [db]} [_ symbol]]
|
||||||
{:db (-> (assoc-in db [:wallet :send-transaction :symbol] symbol)
|
{:db (-> (assoc-in db [:wallet :send-transaction :symbol] symbol)
|
||||||
(assoc-in [:wallet :send-transaction :gas] (estimated-gas symbol)))}))
|
(assoc-in [:wallet :send-transaction :gas] (ethereum/estimate-gas symbol)))}))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet.send/toggle-advanced
|
:wallet.send/toggle-advanced
|
||||||
|
|
|
@ -189,7 +189,7 @@
|
||||||
(when on-press
|
(when on-press
|
||||||
[vector-icons/icon :icons/forward {:color :white}])]]]])
|
[vector-icons/icon :icons/forward {:color :white}])]]]])
|
||||||
|
|
||||||
(defn- send-transaction-panel [{:keys [modal? transaction scroll advanced?] :as transaction}]
|
(defn- send-transaction-panel [{:keys [modal? transaction scroll advanced? symbol]}]
|
||||||
(let [{:keys [amount amount-error signing? to to-name sufficient-funds? in-progress? from-chat?]} transaction]
|
(let [{:keys [amount amount-error signing? to to-name sufficient-funds? in-progress? from-chat?]} transaction]
|
||||||
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
|
@ -219,7 +219,9 @@
|
||||||
[react/view wallet.styles/choose-currency-container
|
[react/view wallet.styles/choose-currency-container
|
||||||
[components/view-currency wallet.styles/choose-currency]]
|
[components/view-currency wallet.styles/choose-currency]]
|
||||||
[react/view wallet.styles/choose-currency-container
|
[react/view wallet.styles/choose-currency-container
|
||||||
[components/choose-currency wallet.styles/choose-currency]])]
|
[components/choose-currency {:style wallet.styles/choose-currency
|
||||||
|
:on-change #(re-frame/dispatch [:wallet.send/set-symbol (keyword %)])
|
||||||
|
:value (name symbol)}]])]
|
||||||
[react/view {:style send.styles/advanced-wrapper}
|
[react/view {:style send.styles/advanced-wrapper}
|
||||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)])}
|
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)])}
|
||||||
[react/view {:style send.styles/advanced-button-wrapper}
|
[react/view {:style send.styles/advanced-button-wrapper}
|
||||||
|
@ -245,15 +247,17 @@
|
||||||
|
|
||||||
(defview send-transaction []
|
(defview send-transaction []
|
||||||
(letsubs [transaction [:wallet.send/transaction]
|
(letsubs [transaction [:wallet.send/transaction]
|
||||||
|
symbol [:wallet.send/symbol]
|
||||||
advanced? [:wallet.send/advanced?]
|
advanced? [:wallet.send/advanced?]
|
||||||
scroll (atom nil)]
|
scroll (atom nil)]
|
||||||
[send-transaction-panel {:modal? false :transaction transaction :scroll scroll :advanced? advanced?}]))
|
[send-transaction-panel {:modal? false :transaction transaction :scroll scroll :advanced? advanced? :symbol symbol}]))
|
||||||
|
|
||||||
(defview send-transaction-modal []
|
(defview send-transaction-modal []
|
||||||
(letsubs [transaction [:wallet.send/unsigned-transaction]
|
(letsubs [transaction [:wallet.send/unsigned-transaction]
|
||||||
|
symbol [:wallet.send/symbol]
|
||||||
advanced? [:wallet.send/advanced?]]
|
advanced? [:wallet.send/advanced?]]
|
||||||
(if transaction
|
(if transaction
|
||||||
[send-transaction-panel {:modal? true :transaction transaction :advanced? advanced?}]
|
[send-transaction-panel {:modal? true :transaction transaction :advanced? advanced? :symbol symbol}]
|
||||||
[react/view wallet.styles/wallet-modal-container
|
[react/view wallet.styles/wallet-modal-container
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
[status-bar/status-bar {:type :modal-wallet}]
|
[status-bar/status-bar {:type :modal-wallet}]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns status-im.utils.ethereum.core
|
(ns status-im.utils.ethereum.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[status-im.js-dependencies :as dependencies]
|
[status-im.js-dependencies :as dependencies]
|
||||||
|
[status-im.utils.ethereum.tokens :as tokens]
|
||||||
[status-im.utils.money :as money]))
|
[status-im.utils.money :as money]))
|
||||||
|
|
||||||
;; IDs standardized in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids
|
;; IDs standardized in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids
|
||||||
|
@ -83,3 +84,9 @@
|
||||||
|
|
||||||
(def default-transaction-gas (money/bignumber 21000))
|
(def default-transaction-gas (money/bignumber 21000))
|
||||||
(def default-gas-price (money/->wei :gwei 21))
|
(def default-gas-price (money/->wei :gwei 21))
|
||||||
|
|
||||||
|
(defn estimate-gas [symbol]
|
||||||
|
(if (tokens/ethereum? symbol)
|
||||||
|
default-transaction-gas
|
||||||
|
;; TODO(jeluard) Rely on estimateGas call
|
||||||
|
(.times default-transaction-gas 5)))
|
|
@ -23,21 +23,23 @@
|
||||||
(def key-value-format (str "([^" parameter-separator key-value-separator "]+)"))
|
(def key-value-format (str "([^" parameter-separator key-value-separator "]+)"))
|
||||||
(def query-pattern (re-pattern (str key-value-format key-value-separator key-value-format)))
|
(def query-pattern (re-pattern (str key-value-format key-value-separator key-value-format)))
|
||||||
|
|
||||||
(def valid-native-arguments #{:value :gas})
|
(def valid-native-arguments #{:value :gas :gasPrice})
|
||||||
|
|
||||||
(defn- parse-query [s]
|
(defn- parse-query [s]
|
||||||
(into {} (for [[_ k v] (re-seq query-pattern (or s ""))]
|
(into {} (for [[_ k v] (re-seq query-pattern (or s ""))]
|
||||||
[(keyword k) v])))
|
[(keyword k) v])))
|
||||||
|
|
||||||
(defn- parse-native-arguments [m]
|
(defn- parse-native-arguments [m]
|
||||||
(when (set/superset? valid-native-arguments (set (keys m)))
|
(select-keys m valid-native-arguments))
|
||||||
m))
|
|
||||||
|
|
||||||
(defn- parse-arguments [function-name s]
|
(defn- parse-arguments [function-name s]
|
||||||
(let [m (parse-query s)]
|
(let [m (parse-query s)
|
||||||
|
arguments (parse-native-arguments m)]
|
||||||
(if function-name
|
(if function-name
|
||||||
(merge {:function-name function-name} (when-not (empty? m) {:function-arguments m}))
|
(merge arguments {:function-name function-name}
|
||||||
(parse-native-arguments m))))
|
(when (seq m)
|
||||||
|
{:function-arguments (apply dissoc m valid-native-arguments)}))
|
||||||
|
arguments)))
|
||||||
|
|
||||||
;; TODO add ENS support
|
;; TODO add ENS support
|
||||||
|
|
||||||
|
@ -94,5 +96,16 @@
|
||||||
(str chain-id-separator chain-id))
|
(str chain-id-separator chain-id))
|
||||||
(when-not (empty? parameters)
|
(when-not (empty? parameters)
|
||||||
(if function-name
|
(if function-name
|
||||||
(str function-name-separator function-name query-separator (generate-query-string function-arguments))
|
(str function-name-separator function-name query-separator
|
||||||
|
(let [native-parameters (dissoc parameters :function-name :function-arguments)]
|
||||||
|
(generate-query-string (merge function-arguments native-parameters))))
|
||||||
(str query-separator (generate-query-string parameters))))))))
|
(str query-separator (generate-query-string parameters))))))))
|
||||||
|
|
||||||
|
(defn generate-erc20-uri
|
||||||
|
"Generate a EIP 681 URI encapsulating ERC20 token transfer"
|
||||||
|
[address {:keys [symbol value chain-id] :as m}]
|
||||||
|
(when-let [token (tokens/symbol->token (or (ethereum/chain-id->chain-keyword chain-id) :mainnet) symbol)]
|
||||||
|
(generate-uri (:address token)
|
||||||
|
(merge (dissoc m :value :symbol)
|
||||||
|
{:function-name "transfer"
|
||||||
|
:function-arguments {:uint256 value :address address}}))))
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
(ns status-im.utils.ethereum.tokens
|
(ns status-im.utils.ethereum.tokens
|
||||||
(:require [status-im.ui.components.styles :as styles]
|
(:require [status-im.ui.components.styles :as styles])
|
||||||
[status-im.utils.ethereum.core :as ethereum])
|
|
||||||
(:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons]]))
|
(:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons]]))
|
||||||
|
|
||||||
(defn- asset-border [color]
|
(defn- asset-border [color]
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
(is (= nil(eip681/parse-uri "ethereum:0x1234")))
|
(is (= nil(eip681/parse-uri "ethereum:0x1234")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1")))
|
||||||
(is (= nil (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?unknown=1")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?unknown=1")))
|
||||||
(is (= nil (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "2.014e18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=2.014e18")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "2.014e18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=2.014e18")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "-1e18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=-1e18")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "-1e18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=-1e18")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "+1E18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=+1E18")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "+1E18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=+1E18")))
|
||||||
|
@ -24,7 +24,21 @@
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@1?value=1e18&gas=5000")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@1?value=1e18&gas=5000")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 3} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1e18&gas=5000")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 3} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1e18&gas=5000")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer"} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer")))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer"} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer")))
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1"))))
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}
|
||||||
|
(eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1")))
|
||||||
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :gas "100" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}
|
||||||
|
(eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1&gas=100"))))
|
||||||
|
|
||||||
|
(deftest generate-erc20-uri
|
||||||
|
(is (= nil (eip681/generate-erc20-uri nil nil)))
|
||||||
|
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5})))
|
||||||
|
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7&gas=10000&gasPrice=10000"
|
||||||
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5 :gas 10000 :gasPrice 10000})))
|
||||||
|
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :chain-id 1 :value 5})))
|
||||||
|
(is (= "ethereum:0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :STT :chain-id 3 :value 5}))))
|
||||||
|
|
||||||
(deftest generate-uri
|
(deftest generate-uri
|
||||||
(is (= nil (eip681/generate-uri nil nil)))
|
(is (= nil (eip681/generate-uri nil nil)))
|
||||||
|
@ -35,7 +49,18 @@
|
||||||
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1000000000000000000" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1e18)})))
|
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1000000000000000000" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1e18)})))
|
||||||
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1&gas=100" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1) :gas (money/bignumber 100) :chain-id 1})))
|
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1&gas=100" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1) :gas (money/bignumber 100) :chain-id 1})))
|
||||||
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1&gas=100" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1) :gas (money/bignumber 100) :chain-id 3})))
|
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1&gas=100" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1) :gas (money/bignumber 100) :chain-id 3})))
|
||||||
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1" (eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:value (money/bignumber 1) :gas (money/bignumber 100) :chain-id 1 :function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 1}}))))
|
(is (= "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1&gas=100"
|
||||||
|
(eip681/generate-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
|
{:gas (money/bignumber 100) :chain-id 1 :function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 1}}))))
|
||||||
|
|
||||||
|
(deftest round-trip
|
||||||
|
(let [uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1&gas=100"
|
||||||
|
{:keys [address] :as params} (eip681/parse-uri uri)]
|
||||||
|
(is (= uri (eip681/generate-uri address (dissoc params :address)))))
|
||||||
|
(let [uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3/transfer?uint256=5&address=0xc55cf4b03948d7ebc8b9e8bad92643703811d162"
|
||||||
|
{:keys [address] :as params} (eip681/parse-uri uri)]
|
||||||
|
(is (= uri (eip681/generate-uri address (dissoc params :address))))))
|
||||||
|
|
||||||
|
|
||||||
(deftest parse-eth-value
|
(deftest parse-eth-value
|
||||||
(is (= nil (eip681/parse-eth-value nil)))
|
(is (= nil (eip681/parse-eth-value nil)))
|
||||||
|
|
Loading…
Reference in New Issue