diff --git a/src/status_im/browser/core.cljs b/src/status_im/browser/core.cljs index 81230516bb92..a33cb40741b3 100644 --- a/src/status_im/browser/core.cljs +++ b/src/status_im/browser/core.cljs @@ -297,16 +297,14 @@ :webview webview-bridge}}) (defn normalize-sign-message-params - "NOTE (andrey) we need this function, because params may be mixed up, - so we need to figure out which one is address and which message" + "NOTE (andrey) we need this function, because params may be mixed up" [params] - (let [[first-param second-param] params - first-param-address? (ethereum/address? first-param) - second-param-address? (ethereum/address? second-param)] - (when (or first-param-address? second-param-address?) - (if first-param-address? - [first-param second-param] - [second-param first-param])))) + (let [[first-param second-param] params] + (cond + (ethereum/address? first-param) + [first-param second-param] + (ethereum/address? second-param) + [second-param first-param]))) (fx/defn web3-send-async [cofx {:keys [method params id] :as payload} message-id] diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index db3c846b933c..141ab36bbe8e 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -238,6 +238,10 @@ ;; (ethereum/sha3 "Transfer(address,address,uint256)") (def ^:const event-transfer-hash "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") +(def ^:const method-id-transfer "0xa9059cbb") +(def ^:const method-id-approve "0x095ea7b3") +(def ^:const method-id-approve-and-call "0xcae9ca51") + (def regx-emoji #"^((?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F|[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF])+$") (def regx-rtl-characters #"[^\u0591-\u06EF\u06FA-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]*?[\u0591-\u06EF\u06FA-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]") (def regx-url #"(?i)(?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9\-]+[.][a-z]{1,4}/?)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'\".,<>?«»“”‘’]){0,}") diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index cd54094ac3bf..137c25eb56e0 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -13,7 +13,7 @@ "eth_getBalance" {:on-result money/bignumber} "eth_estimateGas" - {:on-result money/bignumber} + {:on-result #(money/bignumber (int (* % 1.2)))} "eth_gasPrice" {:on-result money/bignumber} "eth_getBlockByHash" diff --git a/src/status_im/signing/core.cljs b/src/status_im/signing/core.cljs index c8763e797a93..8c0f5366db57 100644 --- a/src/status_im/signing/core.cljs +++ b/src/status_im/signing/core.cljs @@ -55,6 +55,7 @@ (let [unmasked-pass (security/safe-unmask-data password)] {:db (update db :signing/sign assoc :password password + :error nil :enabled? (and unmasked-pass (> (count unmasked-pass) 5)))})) (fx/defn sign-message @@ -111,17 +112,30 @@ :gas-price (money/to-fixed (money/bignumber gasPrice)) :gas-limit (money/to-fixed (money/bignumber gas))})})) +(defn get-method-type [data] + (cond + (string/starts-with? data constants/method-id-transfer) + :transfer + (string/starts-with? data constants/method-id-approve) + :approve + (string/starts-with? data constants/method-id-approve-and-call) + :approve-and-call)) + (defn get-transfer-token [db to data] (let [{:keys [symbol decimals] :as token} (tokens/address->token (:wallet/all-tokens db) (ethereum/chain-keyword db) to)] - (when (and token data (string? data) (string/starts-with? data (abi-spec/signature->method-id "transfer(address,uint256)"))) - (let [[address value] (abi-spec/decode (str "0x" (subs data 10)) ["address" "uint256"])] - (when (and address value) - {:to address - :contact (get-contact db address) - :contract to - :amount (money/to-fixed (money/token->unit value decimals)) - :token token - :symbol symbol}))))) + (when (and token data (string? data)) + (when-let [type (get-method-type data)] + (let [[address value _] (abi-spec/decode + (str "0x" (subs data 10)) + (if (= type :approve-and-call) ["address" "uint256" "bytes"] ["address" "uint256"]))] + (when (and address value) + {:to address + :contact (get-contact db address) + :contract to + :approve? (not= type :transfer) + :amount (money/to-fixed (money/token->unit value decimals)) + :token token + :symbol symbol})))))) (defn parse-tx-obj [db {:keys [to value data]}] (if (nil? to) @@ -130,7 +144,7 @@ eth-amount (when eth-value (money/to-number (money/wei->ether eth-value))) token (get-transfer-token db to data)] (cond - (and eth-amount (not (zero? eth-amount))) + (and eth-amount (or (not (zero? eth-amount)) (nil? data))) {:to to :contact (get-contact db to) :symbol :ETH diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 024f9d8d4917..acc52fc80bf9 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -1887,8 +1887,8 @@ :signing/amount-errors :<- [:signing/tx] :<- [:balance] - (fn [[{:keys [amount token gas gasPrice]} balance]] - (if (and amount token) + (fn [[{:keys [amount token gas gasPrice approve?]} balance]] + (if (and amount token (not approve?)) (let [amount-bn (money/formatted->internal (money/bignumber amount) (:symbol token) (:decimals token)) amount-error (or (get-amount-error amount (:decimals token)) (get-sufficient-funds-error balance (:symbol token) amount-bn))] diff --git a/src/status_im/ui/screens/signing/views.cljs b/src/status_im/ui/screens/signing/views.cljs index b82e18c81908..b25834ded5dd 100644 --- a/src/status_im/ui/screens/signing/views.cljs +++ b/src/status_im/ui/screens/signing/views.cljs @@ -63,7 +63,7 @@ [chat-icon/custom-icon-view-list (:name token) color 32])]}] [separator]])) -(defn header [{:keys [in-progress?] :as sign} {:keys [contact amount token] :as tx} display-symbol fee fee-display-symbol] +(defn header [{:keys [in-progress?] :as sign} {:keys [contact amount token approve?] :as tx} display-symbol fee fee-display-symbol] [react/view styles/header (when sign [react/touchable-highlight (when-not in-progress? {:on-press #(re-frame/dispatch [:set :signing/sign nil])}) @@ -71,7 +71,8 @@ [icons/icon :main-icons/back]]]) [react/view {:flex 1} (if amount - [react/text {:style {:typography :title-bold}} (str (i18n/label :t/sending) " " amount " " display-symbol)] + [react/text {:style {:typography :title-bold}} (str (if approve? (i18n/label :t/approving) (i18n/label :t/sending)) + " " amount " " display-symbol)] [react/text {:style {:typography :title-bold}} (i18n/label :t/contract-interaction)]) (if sign [react/nested-text {:style {:color colors/gray} @@ -81,7 +82,8 @@ [react/text {:style {:margin-top 6 :color colors/gray}} (str fee " " fee-display-symbol " " (string/lower-case (i18n/label :t/network-fee)))])] [react/touchable-highlight (when-not in-progress? {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])}) - [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]) + [react/view {:padding 6} + [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]]) (views/defview password-view [{:keys [type error in-progress? enabled?]}] (views/letsubs [phrase [:signing/phrase]] @@ -115,7 +117,8 @@ [react/view styles/message-header [react/text {:style {:typography :title-bold}} (i18n/label :t/signing-a-message)] [react/touchable-highlight {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])} - [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]] + [react/view {:padding 6} + [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]] [separator] [react/view {:padding-top 16} [react/view styles/message-border @@ -123,7 +126,7 @@ [react/text (or formatted-data "")]]] [password-view sign]]])) -(views/defview sheet [{:keys [contact amount token] :as tx}] +(views/defview sheet [{:keys [contact amount token approve?] :as tx}] (views/letsubs [fee [:signing/fee] sign [:signing/sign] chain [:ethereum/chain-keyword] @@ -140,12 +143,13 @@ [contact-item contact] [separator] [token-item token display-symbol] - [react/view - [list-item/list-item {:type :small :title (i18n/label :t/send-request-amount) - :error amount-error - :accessories [[acc-text (if amount (str amount) "0") - (or display-symbol fee-display-symbol)]]}] - [separator]] + (when-not approve? + [react/view + [list-item/list-item {:type :small :title (i18n/label :t/send-request-amount) + :error amount-error + :accessories [[acc-text (if amount (str amount) "0") + (or display-symbol fee-display-symbol)]]}] + [separator]]) [list-item/list-item {:type :small :title (i18n/label :t/network-fee) :error gas-error :accessories [[acc-text fee fee-display-symbol] :chevron] @@ -157,41 +161,44 @@ :disabled? (or amount-error gas-error)} (i18n/label :t/sign-with-password)]]])]))) -(views/defview signing-view [tx window-height] - (views/letsubs [bottom-anim-value (anim/create-value (- window-height)) - alpha-value (anim/create-value 0) - current-tx (reagent/atom nil) - update? (reagent/atom nil)] - {:component-will-update (fn [_ [_ tx _]] - (cond - @update? - (do (reset! update? false) - (show-panel-anim bottom-anim-value alpha-value)) +(defn signing-view [tx window-height] + (let [bottom-anim-value (anim/create-value (- window-height)) + alpha-value (anim/create-value 0) + current-tx (reagent/atom nil) + update? (reagent/atom nil)] + (reagent/create-class + {:component-will-update (fn [_ [_ tx _]] + (cond + @update? + (do (reset! update? false) + (show-panel-anim bottom-anim-value alpha-value)) - (and @current-tx tx) - (do (reset! update? true) - (js/setTimeout #(reset! current-tx tx) 600) - (hide-panel-anim bottom-anim-value alpha-value (- window-height))) + (and @current-tx tx) + (do (reset! update? true) + (js/setTimeout #(reset! current-tx tx) 600) + (hide-panel-anim bottom-anim-value alpha-value (- window-height))) - tx - (do (reset! current-tx tx) - (show-panel-anim bottom-anim-value alpha-value)) + tx + (do (reset! current-tx tx) + (show-panel-anim bottom-anim-value alpha-value)) - :else - (do (js/setTimeout #(reset! current-tx nil) 500) - (hide-panel-anim bottom-anim-value alpha-value (- window-height)))))} - (when @current-tx - [react/view {:position :absolute :top 0 :bottom 0 :left 0 :right 0} - [react/animated-view {:flex 1 :background-color :black :opacity alpha-value}] - [react/animated-view {:position :absolute :height window-height :left 0 :right 0 :bottom bottom-anim-value} - [react/keyboard-avoiding-view {:style {:flex 1}} - [react/view {:flex 1}] - (if (:message @current-tx) - [message-sheet] - [sheet @current-tx])]]]))) + :else + (do (js/setTimeout #(reset! current-tx nil) 500) + (hide-panel-anim bottom-anim-value alpha-value (- window-height))))) + :reagent-render (fn [] + (when @current-tx + [react/view {:position :absolute :top 0 :bottom 0 :left 0 :right 0} + [react/animated-view {:flex 1 :background-color :black :opacity alpha-value}] + [react/animated-view {:position :absolute :height window-height :left 0 :right 0 + :bottom bottom-anim-value} + [react/keyboard-avoiding-view {:style {:flex 1}} + [react/view {:flex 1}] + (if (:message @current-tx) + [message-sheet] + [sheet @current-tx])]]]))}))) (views/defview signing [] (views/letsubs [tx [:signing/tx] {window-height :height} [:dimensions/window]] ;;we use select-keys here because we don't want to update view if other keys in map is changed - [signing-view (when tx (select-keys tx [:contact :amount :token :message])) window-height])) \ No newline at end of file + [signing-view (when tx (select-keys tx [:contact :amount :token :approve? :message])) window-height])) \ No newline at end of file diff --git a/translations/en.json b/translations/en.json index 5d0d058604bd..9b1dd6cf82e0 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1067,9 +1067,10 @@ "report-bug-email-template": "1. Issue Description\n(Describe the feature you would like, or briefly summarise the bug and what you did, what you expected to happen, and what actually happens. Sections below)\n\n\n2. Steps to reproduce\n(Describe how we can replicate the bug step by step.)\n-Open Status\n-...\n-Step 3, etc.\n\n\n3. Expected behavior\n(Describe what you expected to happen.)\n\n\n4. Actual behavior\n(Describe what actually happened.)\n\n\n5. Attach screenshots that can demo the problem, please\n", "update" : "Update", "sending" : "Sending", + "approving" : "Approving", "contract-interaction" : "Contract interaction", "signing-phrase" : "Signing phrase", - "sign-with-password" : "Sign with password", "network-fee" : "Network fee", + "sign-with-password" : "Sign with password", "signing-a-message" : "Signing a message" }