From f90e1a4ed32642874c3e4b0bafcba691613c7bcc Mon Sep 17 00:00:00 2001 From: Julien Eluard Date: Fri, 5 Jan 2018 08:12:56 +0100 Subject: [PATCH] [BUG #2029] Properly handle gas details from payment requests --- .../wallet/choose_recipient/events.cljs | 26 ++++++--- .../ui/screens/wallet/components/views.cljs | 9 ++- .../ui/screens/wallet/request/db.cljs | 3 +- .../ui/screens/wallet/request/events.cljs | 5 ++ .../ui/screens/wallet/request/subs.cljs | 7 ++- .../ui/screens/wallet/request/views.cljs | 56 +++++++++++-------- .../ui/screens/wallet/send/events.cljs | 8 +-- .../ui/screens/wallet/send/views.cljs | 12 ++-- src/status_im/utils/ethereum/core.cljs | 9 ++- src/status_im/utils/ethereum/eip681.cljs | 29 +++++++--- src/status_im/utils/ethereum/tokens.cljs | 3 +- .../status_im/test/utils/ethereum/eip681.cljs | 33 +++++++++-- 12 files changed, 134 insertions(+), 66 deletions(-) diff --git a/src/status_im/ui/screens/wallet/choose_recipient/events.cljs b/src/status_im/ui/screens/wallet/choose_recipient/events.cljs index 4ad48ad276..7a2fc72f65 100644 --- a/src/status_im/ui/screens/wallet/choose_recipient/events.cljs +++ b/src/status_im/ui/screens/wallet/choose_recipient/events.cljs @@ -3,7 +3,8 @@ [status-im.i18n :as i18n] [status-im.utils.ethereum.core :as ethereum] [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 :wallet/toggle-flashlight @@ -12,37 +13,44 @@ toggled-state (if (= :on flashlight-state) :off :on)] (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 db [:wallet :send-transaction] - #(cond-> (assoc % :to address :to-name name) - amount (assoc :amount amount)))) + #(cond-> (assoc % :to address) + 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 "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] (or (let [m (eip681/parse-uri s)] (merge m (eip681/extract-request-details m))) (when (ethereum/address? s) - {:address s :chain-id chain-id :symbol :ETH}))) + {:address s :chain-id chain-id}))) (handlers/register-handler-fx :wallet/fill-request-from-url (fn [{{:keys [web3 network] :as db} :db} [_ data name]] (let [{:keys [view-id]} db 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))] (cond-> {:db db} (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})) (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 :wallet/fill-request-from-contact (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] [:navigate-back]]})) diff --git a/src/status_im/ui/screens/wallet/components/views.cljs b/src/status_im/ui/screens/wallet/components/views.cljs index cfec435262..a4b8967f42 100644 --- a/src/status_im/ui/screens/wallet/components/views.cljs +++ b/src/status_im/ui/screens/wallet/components/views.cljs @@ -62,17 +62,16 @@ [react/text (name symbol)]]])) -(views/defview choose-currency [style] - (views/letsubs [visible-tokens [:wallet.settings/visible-tokens] - symbol [:wallet.send/symbol]] +(views/defview choose-currency [{:keys [style on-change value]}] + (views/letsubs [visible-tokens [:wallet.settings/visible-tokens]] [react/view [react/text {:style styles/label} (i18n/label :t/currency)] [react/view (merge styles/currency-container style) - [react/picker {:selected (name symbol) + [react/picker {:selected value :style {:color "white"} :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)))]]])) (defn choose-recipient-content [{:keys [address name on-press style]}] diff --git a/src/status_im/ui/screens/wallet/request/db.cljs b/src/status_im/ui/screens/wallet/request/db.cljs index ad87cf3681..9bf64c85f6 100644 --- a/src/status_im/ui/screens/wallet/request/db.cljs +++ b/src/status_im/ui/screens/wallet/request/db.cljs @@ -5,6 +5,7 @@ (spec/def ::amount (spec/nilable money/valid?)) (spec/def ::amount-error (spec/nilable string?)) +(spec/def ::symbol (spec/nilable keyword?)) (spec/def :wallet/request-transaction (allowed-keys - :opt-un [::amount ::amount-error])) \ No newline at end of file + :opt-un [::amount ::amount-error ::symbol])) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/request/events.cljs b/src/status_im/ui/screens/wallet/request/events.cljs index a08544666b..480ea65ce3 100644 --- a/src/status_im/ui/screens/wallet/request/events.cljs +++ b/src/status_im/ui/screens/wallet/request/events.cljs @@ -32,3 +32,8 @@ {:db (-> db (assoc-in [:wallet/request-transaction :amount] (money/ether->wei value)) (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)})) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/request/subs.cljs b/src/status_im/ui/screens/wallet/request/subs.cljs index 99e2176695..2390b7944e 100644 --- a/src/status_im/ui/screens/wallet/request/subs.cljs +++ b/src/status_im/ui/screens/wallet/request/subs.cljs @@ -1,11 +1,14 @@ (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 :wallet.request/request-enabled? :<- [:get-in [:wallet/request-transaction :amount]] :<- [:get-in [:wallet/request-transaction :amount-error]] - (fn [[amount amount-error]] + :<- [:get-in [:wallet/request-transaction :symbol]] + (fn [[amount amount-error symbol]] (and + (or (nil? symbol) (tokens/ethereum? symbol)) (nil? amount-error) (not (nil? amount))))) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/request/views.cljs b/src/status_im/ui/screens/wallet/request/views.cljs index 57d4911d17..cd3613008a 100644 --- a/src/status_im/ui/screens/wallet/request/views.cljs +++ b/src/status_im/ui/screens/wallet/request/views.cljs @@ -1,23 +1,23 @@ (ns status-im.ui.screens.wallet.request.views (:require-macros [status-im.utils.views :as views]) - (:require - [re-frame.core :as re-frame] - [status-im.ui.components.react :as react] - [status-im.ui.components.qr-code :as components.qr-code] - [status-im.ui.components.toolbar.actions :as actions] - [status-im.ui.components.toolbar.view :as toolbar] - [status-im.ui.components.status-bar.view :as status-bar] - [status-im.ui.screens.wallet.styles :as wallet.styles] - [status-im.ui.components.common.common :as common] - [status-im.ui.components.icons.vector-icons :as vi] - [status-im.ui.screens.wallet.components.views :as components] - [status-im.ui.screens.wallet.request.styles :as styles] - [status-im.ui.components.styles :as components.styles] - [status-im.i18n :as i18n] - [status-im.utils.platform :as platform] - [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.ethereum.eip681 :as eip681] - [status-im.utils.money :as money])) + (:require [re-frame.core :as re-frame] + [status-im.ui.components.react :as react] + [status-im.ui.components.qr-code :as components.qr-code] + [status-im.ui.components.toolbar.actions :as actions] + [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.screens.wallet.styles :as wallet.styles] + [status-im.ui.components.common.common :as common] + [status-im.ui.components.icons.vector-icons :as vi] + [status-im.ui.screens.wallet.components.views :as components] + [status-im.ui.screens.wallet.request.styles :as styles] + [status-im.ui.components.styles :as components.styles] + [status-im.i18n :as i18n] + [status-im.utils.platform :as platform] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.ethereum.eip681 :as eip681] + [status-im.utils.ethereum.tokens :as tokens] + [status-im.utils.money :as money])) (defn toolbar-view [] [toolbar/toolbar {:style wallet.styles/toolbar :hide-border? true} @@ -31,17 +31,25 @@ :action :request :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] chain-id [:get-network-id]] [components.qr-code/qr-code - {:value (eip681/generate-uri (ethereum/normalized-address (:address account)) (merge {:chain-id chain-id} (when amount {:value amount}))) - :size 256}])) + (let [address (ethereum/normalized-address (:address account)) + params {:chain-id chain-id :value amount :symbol (or symbol :ETH)}] + {:value (generate-value address params) + :size 256})])) (views/defview request-transaction [] ;;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]] amount-error [:get-in [:wallet/request-transaction :amount-error]] + symbol [:get-in [:wallet/request-transaction :symbol]] request-enabled? [:wallet.request/request-enabled?] scroll (atom nil)] [react/keyboard-avoiding-view wallet.styles/wallet-modal-container @@ -52,7 +60,7 @@ [react/view components.styles/flex [react/view styles/network-container [react/view styles/qr-container - [qr-code amount]]] + [qr-code amount symbol]]] [react/view wallet.styles/choose-wallet-container [components/choose-wallet]] [react/view wallet.styles/amount-container @@ -61,7 +69,9 @@ :input-options {:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100))) :on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount %])}}] [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] [react/view wallet.styles/buttons-container [react/touchable-highlight {:style wallet.styles/button :disabled true} diff --git a/src/status_im/ui/screens/wallet/send/events.cljs b/src/status_im/ui/screens/wallet/send/events.cljs index af9705aa24..71bae88fc2 100644 --- a/src/status_im/ui/screens/wallet/send/events.cljs +++ b/src/status_im/ui/screens/wallet/send/events.cljs @@ -70,17 +70,11 @@ (assoc-in [:wallet :send-transaction :amount] (money/ether->wei value)) (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 :wallet.send/set-symbol (fn [{:keys [db]} [_ 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 :wallet.send/toggle-advanced diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index 51b5cfa607..2b3b722370 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -189,7 +189,7 @@ (when on-press [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] [react/keyboard-avoiding-view wallet.styles/wallet-modal-container [react/view components.styles/flex @@ -219,7 +219,9 @@ [react/view wallet.styles/choose-currency-container [components/view-currency wallet.styles/choose-currency]] [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/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)])} [react/view {:style send.styles/advanced-button-wrapper} @@ -245,15 +247,17 @@ (defview send-transaction [] (letsubs [transaction [:wallet.send/transaction] + symbol [:wallet.send/symbol] advanced? [:wallet.send/advanced?] 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 [] (letsubs [transaction [:wallet.send/unsigned-transaction] + symbol [:wallet.send/symbol] advanced? [:wallet.send/advanced?]] (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 components.styles/flex [status-bar/status-bar {:type :modal-wallet}] diff --git a/src/status_im/utils/ethereum/core.cljs b/src/status_im/utils/ethereum/core.cljs index a082a6d67f..cc628e8e74 100644 --- a/src/status_im/utils/ethereum/core.cljs +++ b/src/status_im/utils/ethereum/core.cljs @@ -1,6 +1,7 @@ (ns status-im.utils.ethereum.core (:require [clojure.string :as string] [status-im.js-dependencies :as dependencies] + [status-im.utils.ethereum.tokens :as tokens] [status-im.utils.money :as money])) ;; IDs standardized in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids @@ -82,4 +83,10 @@ (.sendTransaction (.-eth web3) (clj->js params) cb)) (def default-transaction-gas (money/bignumber 21000)) -(def default-gas-price (money/->wei :gwei 21)) \ No newline at end of file +(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))) \ No newline at end of file diff --git a/src/status_im/utils/ethereum/eip681.cljs b/src/status_im/utils/ethereum/eip681.cljs index 7bd2783d95..a40157416a 100644 --- a/src/status_im/utils/ethereum/eip681.cljs +++ b/src/status_im/utils/ethereum/eip681.cljs @@ -23,21 +23,23 @@ (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 valid-native-arguments #{:value :gas}) +(def valid-native-arguments #{:value :gas :gasPrice}) (defn- parse-query [s] (into {} (for [[_ k v] (re-seq query-pattern (or s ""))] [(keyword k) v]))) (defn- parse-native-arguments [m] - (when (set/superset? valid-native-arguments (set (keys m))) - m)) + (select-keys m valid-native-arguments)) (defn- parse-arguments [function-name s] - (let [m (parse-query s)] + (let [m (parse-query s) + arguments (parse-native-arguments m)] (if function-name - (merge {:function-name function-name} (when-not (empty? m) {:function-arguments m})) - (parse-native-arguments m)))) + (merge arguments {:function-name function-name} + (when (seq m) + {:function-arguments (apply dissoc m valid-native-arguments)})) + arguments))) ;; TODO add ENS support @@ -94,5 +96,16 @@ (str chain-id-separator chain-id)) (when-not (empty? parameters) (if function-name - (str function-name-separator function-name query-separator (generate-query-string function-arguments)) - (str query-separator (generate-query-string parameters)))))))) \ No newline at end of file + (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)))))))) + +(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}})))) diff --git a/src/status_im/utils/ethereum/tokens.cljs b/src/status_im/utils/ethereum/tokens.cljs index be0b28d979..2b76f805a8 100644 --- a/src/status_im/utils/ethereum/tokens.cljs +++ b/src/status_im/utils/ethereum/tokens.cljs @@ -1,6 +1,5 @@ (ns status-im.utils.ethereum.tokens - (:require [status-im.ui.components.styles :as styles] - [status-im.utils.ethereum.core :as ethereum]) + (:require [status-im.ui.components.styles :as styles]) (:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons]])) (defn- asset-border [color] diff --git a/test/cljs/status_im/test/utils/ethereum/eip681.cljs b/test/cljs/status_im/test/utils/ethereum/eip681.cljs index ba0fbec0ac..edaa13fd71 100644 --- a/test/cljs/status_im/test/utils/ethereum/eip681.cljs +++ b/test/cljs/status_im/test/utils/ethereum/eip681.cljs @@ -13,8 +13,8 @@ (is (= nil(eip681/parse-uri "ethereum:0x1234"))) (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 (= nil (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?unknown=1"))) + (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 "-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 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" :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 (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=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/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 (is (= nil (eip681/parse-eth-value nil)))