feat(swap): swap confirmation screen (#20669)

Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
Brian Sztamfater 2024-07-14 00:51:02 -03:00 committed by GitHub
parent 12b8dcf1e7
commit 5f085e9cea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 301 additions and 14 deletions

View File

@ -5,8 +5,9 @@
[:catn
[:props
[:map
[:type [:enum :status-account :saved-account :account :user]]
[:type [:enum :status-account :saved-account :account :user :token]]
[:account-props {:optional true} [:maybe :map]]
[:token-props {:optional true} [:maybe :map]]
[:networks? {:optional true} [:maybe :boolean]]
[:values {:optional true} [:maybe :map]]]]]
:any])

View File

@ -4,6 +4,7 @@
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.avatars.wallet-user-avatar.view :as wallet-user-avatar]
[quo.components.markdown.text :as text]
[quo.components.utilities.token.view :as token]
[quo.components.wallet.summary-info.schema :as summary-info-schema]
[quo.components.wallet.summary-info.style :as style]
[quo.foundations.colors :as colors]
@ -58,13 +59,14 @@
:theme theme}])]))
(defn- view-internal
[{:keys [type account-props networks? values]}]
[{:keys [type account-props token-props networks? values]}]
(let [theme (quo.theme/use-theme)]
[rn/view
{:style (style/container networks? theme)}
[rn/view
{:style style/info-container}
(case type
:token [token/view (select-keys token-props #{:token :size})]
:status-account [account-avatar/view account-props]
:saved-account [wallet-user-avatar/wallet-user-avatar (assoc account-props :size :size-32)]
:account [wallet-user-avatar/wallet-user-avatar
@ -73,7 +75,8 @@
:neutral? true)]
[user-avatar/user-avatar account-props])
[rn/view {:style {:margin-left 8}}
(when (not= type :account) [text/text {:weight :semi-bold} (:name account-props)])
(when (not= type :account)
[text/text {:weight :semi-bold} (or (:name account-props) (:label token-props))])
[rn/view
{:style {:flex-direction :row
:align-items :center}}
@ -91,7 +94,7 @@
:weight (when (= type :account) :semi-bold)
:style {:color (when (not= type :account)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}}
(:address account-props)]]]]
(or (:address account-props) (:address token-props))]]]]
(when networks?
[:<>
[rn/view

View File

@ -566,3 +566,6 @@
(def ^:const default-slippage 0.5)
(def ^:const max-recommended-slippage 5)
(def ^:const max-slippage-decimal-places 2)
(def ^:const swap-default-provider
{:name "Paraswap"
:terms-and-conditions-url "https://files.paraswap.io/tos_v4.pdf"})

View File

@ -42,3 +42,23 @@
(rf/reg-event-fx :wallet.swap/set-max-slippage
(fn [{:keys [db]} [max-slippage]]
{:db (assoc-in db [:wallet :ui :swap :max-slippage] (utils.number/parse-float max-slippage))}))
(rf/reg-event-fx :wallet.swap/select-asset-to-receive
(fn [{:keys [db]} [{:keys [token]}]]
{:db (assoc-in db [:wallet :ui :swap :asset-to-receive] token)}))
(rf/reg-event-fx :wallet.swap/set-pay-amount
(fn [{:keys [db]} [amount]]
{:db (assoc-in db [:wallet :ui :swap :pay-amount] amount)}))
(rf/reg-event-fx :wallet.swap/set-swap-proposal
(fn [{:keys [db]} [swap-proposal]]
{:db (assoc-in db [:wallet :ui :swap :swap-proposal] swap-proposal)}))
(rf/reg-event-fx :wallet.swap/set-provider
(fn [{:keys [db]}]
{:db (assoc-in db [:wallet :ui :swap :providers] [constants/swap-default-provider])}))
(rf/reg-event-fx :wallet.swap/recalculate-fees
(fn [{:keys [db]} [loading-fees?]]
{:db (assoc-in db [:wallet :ui :swap :loading-fees?] loading-fees?)}))

View File

@ -5,7 +5,6 @@
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.asset-list.view :as asset-list]
[status-im.contexts.wallet.swap.select-asset-to-pay.style :as style]
[status-im.setup.hot-reload :as hot-reload]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@ -19,6 +18,20 @@
:value search-text
:on-change-text on-change-text}]])
(def dummy-swap-proposal
{:from {:chain-id 1
:native-currency-symbol "ETH"}
:to {:chain-id 1
:native-currency-symbol "ETH"}
:gas-amount "23487"
:gas-fees {:base-fee "32.325296406"
:max-priority-fee-per-gas "0.011000001"
:eip1559-enabled true}
:estimated-time 3
:receive-amount 99.98
:receive-token {:symbol "SNT"
:address "0x432492384728934239789"}})
(defn- assets-view
[search-text on-change-text]
(let [on-token-press (fn [token]
@ -27,7 +40,11 @@
{:token token
:network (when (= (count token-networks) 1)
(first token-networks))
:stack-id :screen/wallet.swap-select-asset-to-pay}])))]
:stack-id :screen/wallet.swap-select-asset-to-pay}])
(rf/dispatch [:wallet.swap/select-asset-to-receive {:token token}])
(rf/dispatch [:wallet.swap/set-pay-amount 100])
(rf/dispatch [:wallet.swap/set-swap-proposal dummy-swap-proposal])
(rf/dispatch [:wallet.swap/set-provider])))]
[:<>
[search-input search-text on-change-text]
[asset-list/view
@ -41,8 +58,6 @@
on-close (fn []
(rf/dispatch [:wallet.swap/clean-asset-to-pay])
(rf/dispatch [:navigate-back]))]
(hot-reload/use-safe-unmount (fn []
(rf/dispatch [:wallet.swap/clean-asset-to-pay])))
[rn/safe-area-view {:style style/container}
[account-switcher/view
{:on-press on-close

View File

@ -0,0 +1,39 @@
(ns status-im.contexts.wallet.swap.swap-confirmation.style
(:require [quo.foundations.colors :as colors]))
(def detail-item
{:flex 1
:height 36
:background-color :transparent})
(def content-container
{:padding-top 12
:padding-horizontal 20
:padding-bottom 32})
(def title-container
{:margin-right 4})
(def title-line-with-margin-top
{:flex-direction :row
:margin-top 4})
(def details-container
{:flex-direction :row
:justify-content :space-between
:height 52
:padding-top 7
:margin-bottom 8})
(def summary-section-container
{:padding-horizontal 20
:padding-bottom 16})
(defn section-label
[theme]
{:margin-bottom 8
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
(def providers-container
{:align-items :center
:margin-top 12})

View File

@ -0,0 +1,192 @@
(ns status-im.contexts.wallet.swap.swap-confirmation.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.floating-button-page.view :as floating-button-page]
[status-im.common.standard-authentication.core :as standard-auth]
[status-im.contexts.wallet.swap.swap-confirmation.style :as style]
[utils.address :as address-utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- on-close-action
[]
(rf/dispatch [:navigate-back]))
(defn- swap-title
[{:keys [pay-token-symbol pay-amount receive-token-symbol receive-amount account]}]
[rn/view {:style style/content-container}
[rn/view {:style {:flex-direction :row}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title-container
:accessibility-label :title-label}
(i18n/label :t/swap)]
[quo/summary-tag
{:token pay-token-symbol
:label (str pay-amount " " pay-token-symbol)
:type :token}]]
[rn/view {:style style/title-line-with-margin-top}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title-container
:accessibility-label :title-label}
(i18n/label :t/to)]
[quo/summary-tag
{:token receive-token-symbol
:label (str receive-amount " " receive-token-symbol)
:type :token}]]
[rn/view {:style style/title-line-with-margin-top}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title-container
:accessibility-label :send-label}
(i18n/label :t/in)]
[quo/summary-tag
{:label (:name account)
:type :account
:emoji (:emoji account)
:customization-color (:color account)}]]])
(defn- summary-section
[{:keys [theme label title-accessibility-label amount token-symbol token-address network]}]
(let [network-values {(if (= network :mainnet) :ethereum network)
{:amount amount :token-symbol token-symbol}}]
[rn/view {:style style/summary-section-container}
[quo/text
{:size :paragraph-2
:weight :medium
:style (style/section-label theme)
:accessibility-label title-accessibility-label}
label]
[quo/summary-info
{:type :token
:networks? true
:values network-values
:token-props {:token token-symbol
:label (str amount " " token-symbol)
:address (address-utils/get-shortened-compressed-key token-address)
:size 32}}]]))
(defn- data-item
[{:keys [title subtitle loading?]}]
[quo/data-item
{:container-style style/detail-item
:blur? false
:card? false
:status (if loading? :loading :default)
:size :small
:title title
:subtitle subtitle}])
(defn- transaction-details
[{:keys [estimated-time-min max-fees max-slippage loading-fees?]}]
[rn/view {:style style/details-container}
[:<>
[data-item
{:title (i18n/label :t/est-time)
:subtitle (i18n/label :t/time-in-mins {:minutes (str estimated-time-min)})}]
[data-item
{:title (i18n/label :t/max-fees)
:subtitle max-fees
:loading? loading-fees?}]
[data-item
{:title (i18n/label :t/max-slippage)
:subtitle (str max-slippage "%")}]]])
(defn footer
[{:keys [estimated-time-min native-currency-symbol max-slippage theme account-color provider
loading-fees?]}]
(let [native-token (when native-currency-symbol
(rf/sub [:wallet/token-by-symbol
native-currency-symbol]))
fee-formatted (rf/sub [:wallet/wallet-send-fee-fiat-formatted
native-token])]
[:<>
[transaction-details
{:estimated-time-min estimated-time-min
:max-fees fee-formatted
:max-slippage max-slippage
:loading-fees? loading-fees?
:theme theme}]
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-swap)
:container-style {:z-index 2}
:customization-color account-color
:disabled? loading-fees?
:auth-button-label (i18n/label :t/confirm)}]
[rn/view {:style style/providers-container}
[quo/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-80-opa-40
colors/white-opa-70
theme)}}
(i18n/label :t/swaps-powered-by {:provider (:name provider)})]]]))
(defn view
[]
(let [theme (quo.theme/use-theme)
swap-transaction-data (rf/sub [:wallet/swap])
{:keys [asset-to-pay max-slippage network
pay-amount providers swap-proposal
loading-fees?]} swap-transaction-data
receive-amount (:receive-amount swap-proposal)
receive-token (:receive-token swap-proposal)
receive-token-symbol (:symbol receive-token)
receive-token-address (:address receive-token)
estimated-time-min (:estimated-time swap-proposal)
pay-token-symbol (:symbol asset-to-pay)
pay-token-address (:address asset-to-pay)
native-currency-symbol (get-in swap-proposal [:from :native-currency-symbol])
account (rf/sub [:wallet/current-viewing-account])
account-color (:color account)
provider (first providers)]
[rn/view {:style {:flex 1}}
[floating-button-page/view
{:footer-container-padding 0
:header [quo/page-nav
{:icon-name :i/arrow-left
:on-press on-close-action
:margin-top (safe-area/get-top)
:background :blur
:accessibility-label :top-bar}]
:footer [footer
{:estimated-time-min estimated-time-min
:native-currency-symbol native-currency-symbol
:max-slippage max-slippage
:account-color account-color
:provider provider
:loading-fees? loading-fees?
:theme theme}]
:gradient-cover? true
:customization-color account-color}
[rn/view
[swap-title
{:pay-token-symbol pay-token-symbol
:pay-amount pay-amount
:receive-token-symbol receive-token-symbol
:receive-amount receive-amount
:account account}]
[summary-section
{:title-accessibility-label :summary-section-pay
:label (i18n/label :t/pay)
:token-symbol pay-token-symbol
:amount pay-amount
:token-address pay-token-address
:network (:network-name network)
:theme theme}]
[summary-section
{:title-accessibility-label :summary-section-receive
:label (i18n/label :t/receive)
:token-symbol receive-token-symbol
:amount receive-amount
:token-address receive-token-address
:network (:network-name network)
:theme theme}]]]]))

View File

@ -12,4 +12,8 @@
[quo/button
{:on-press #(rf/dispatch [:show-bottom-sheet
{:content slippage-settings/view}])}
(str "Edit Slippage: " max-slippage "%")]]))
(str "Edit Slippage: " max-slippage "%")]
[quo/button
{:on-press #(rf/dispatch [:navigate-to-within-stack
[:screen/wallet.swap-confirmation :screen/wallet.swap-propasal]])}
"Swap confirmation"]]))

View File

@ -118,6 +118,7 @@
[status-im.contexts.wallet.send.transaction-confirmation.view :as wallet-transaction-confirmation]
[status-im.contexts.wallet.send.transaction-progress.view :as wallet-transaction-progress]
[status-im.contexts.wallet.swap.select-asset-to-pay.view :as wallet-swap-select-asset-to-pay]
[status-im.contexts.wallet.swap.swap-confirmation.view :as wallet-swap-confirmation]
[status-im.contexts.wallet.swap.swap-proposal.view :as wallet-swap-propasal]
[status-im.contexts.wallet.wallet-connect.modals.send-transaction.view :as
wallet-connect-send-transaction]
@ -521,6 +522,10 @@
:options {:insets {:top? true}}
:component wallet-swap-propasal/view}
{:name :screen/wallet.swap-confirmation
:options {:modalPresentationStyle :overCurrentContext}
:component wallet-swap-confirmation/view}
{:name :scan-profile-qr-code
:options (merge
options/dark-screen

View File

@ -52,6 +52,7 @@
fiat-value)]
{:crypto (str crypto-formatted " " token-symbol)
:fiat fiat-formatted})))
(rf/reg-sub
:wallet/swap-max-slippage
:<- [:wallet/swap]

View File

@ -182,7 +182,7 @@
"chat-with-friends": "Chat privately with friends",
"chats": "Chats",
"check-before-syncing": "Check before syncing",
"check-before-syncing-doc-description" :"To sync your devices successfully, make sure to check and complete these steps:",
"check-before-syncing-doc-description": "To sync your devices successfully, make sure to check and complete these steps:",
"check-before-syncing-doc-checkbox-1": "Connect both devices to the same network",
"check-before-syncing-doc-checkbox-2": "Make sure you are logged in on the other device",
"check-before-syncing-doc-checkbox-3": "Disable the firewall and VPN on your devices",
@ -2007,7 +2007,7 @@
"slippage-may-be-higher-than-necessary": "Slippage may be higher than necessary",
"slippage-should-be-more-than-0": "Slippage should be more than 0",
"max-2-decimals": "Max. 2 decimals",
"type-slippage": "Type slippage",
"type-slippage": "Type slippage",
"receive-at-least": "Receive at least",
"select-token-to-swap": "Select token to Swap",
"select-token-to-receive": "Select token to receive",
@ -2651,6 +2651,7 @@
"testnet-not-available": "Testnet not available",
"bridged-to": "Bridged to {{network}}",
"slide-to-bridge": "Slide to bridge",
"slide-to-swap": "Slide to swap",
"provider-is-down": "The provider for the following chain(s) is down: {{chains}}",
"unknown": "Unknown",
"unsupported-file": "Unsupported file",
@ -2746,12 +2747,15 @@
"add-preferences": "Add preferences",
"buy-eth": "Buy ETH",
"not-enough-assets": "Not enough assets to pay gas fees",
"send-from-network" : "Send from {{network}}",
"define-amount-sent-from-network" : "Define amount sent from {{network}} network",
"send-from-network": "Send from {{network}}",
"define-amount-sent-from-network": "Define amount sent from {{network}} network",
"dont-auto-recalculate-network": "Don't auto recalculate {{network}}",
"import-keypair-to-use-account": "Import key pair to use this account",
"import-keypair-steps": "{{account-name}} was derived from your {{keypair-name}} key pair, which has not yet been imported to this device. To transact using this account, you will need to import the {{keypair-name}} key pair first.",
"not-now": "Not now",
"share-usage-data": "Share usage data with Status",
"value-higher-than-send-amount": "This value is higher than entered amount to send"
"value-higher-than-send-amount": "This value is higher than entered amount to send",
"swaps-powered-by": "Swaps powered by {{provider}}",
"max-slippage": "Max slippage",
"pay": "Pay"
}