Skip to content

Commit

Permalink
feat(wallet): add ability to send a token
Browse files Browse the repository at this point in the history
  • Loading branch information
J-Son89 committed Dec 21, 2023
1 parent 4f9544d commit f612de3
Show file tree
Hide file tree
Showing 16 changed files with 370 additions and 281 deletions.
9 changes: 5 additions & 4 deletions src/quo/components/utilities/token/loader.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

(defn- get-token-image*
[token]
(let [token-symbol (cond-> token
(keyword? token) name
:always (comp string/lower-case str))]
(get tokens token-symbol)))
(when token
(let [token-symbol (cond-> token
(keyword? token) name
:always string/lower-case)]
(get tokens token-symbol))))

(def get-token-image (memoize get-token-image*))
8 changes: 4 additions & 4 deletions src/quo/components/utilities/token/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@
(def ^:private b64-png-image-prefix "data:image/png;base64,")

(defn temp-empty-symbol
[token size]
[token size style]
[rn/view
{:style (token-style {:justify-content :center
{:style (token-style (merge {:justify-content :center
:align-items :center
:border-radius 20
:border-width 1
:border-color :grey}
:border-color :grey} style)
size)}
[quo/text {:style {:color :grey}}
(string/capitalize (first (name token)))]])
Expand All @@ -70,6 +70,6 @@
[rn/image
{:style (token-style style size)
:source source}]
[temp-empty-symbol token size])))
[temp-empty-symbol token size style])))

(def view (schema/instrument #'view-internal ?schema))
49 changes: 31 additions & 18 deletions src/quo/components/wallet/summary_info/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
(:require
[quo.components.avatars.account-avatar.view :as account-avatar]
[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.wallet.summary-info.style :as style]
[quo.foundations.colors :as colors]
Expand All @@ -26,34 +27,46 @@

(defn networks
[values theme]
(let [{:keys [ethereum optimism arbitrum]} values]
(let [{:keys [ethereum optimism arbitrum]} values
show-optimism? (pos? optimism)
show-arbitrum? (pos? arbitrum)]
[rn/view
{:style style/networks-container
:accessibility-label :networks}
[network-amount
{:network :ethereum
:amount (str ethereum " ETH")
:divider? true
:theme theme}]
[network-amount
{:network :optimism
:amount (str optimism " ETH")
:divider? true
:theme theme}]
[network-amount
{:network :arbitrum
:amount (str arbitrum " ETH")
:theme theme}]]))
(when (pos? ethereum)
[network-amount
{:network :ethereum
:amount (str ethereum " ETH")
:divider? (or show-arbitrum? show-optimism?)
:theme theme}])
(when show-optimism?
[network-amount
{:network :optimism
:amount (str optimism " OPT")
:divider? show-arbitrum?
:theme theme}])
(when show-arbitrum?
[network-amount
{:network :arbitrum
:amount (str arbitrum " ARB")
:theme theme}])]))

(defn- view-internal
[{:keys [theme type account-props networks? values]}]
[rn/view
{:style (style/container networks? theme)}
[rn/view
{:style style/info-container}
(if (= type :status-account)
[account-avatar/view account-props]
[user-avatar/user-avatar account-props])
(cond (= type :status-account)
[account-avatar/view account-props]
(= type :saved-account)
[wallet-user-avatar/wallet-user-avatar (assoc account-props :size :size-32)]
(= type :account)
[wallet-user-avatar/wallet-user-avatar
(assoc account-props
:size :size-32
:neutral? true )]
:else [user-avatar/user-avatar account-props])
[rn/view {:style {:margin-left 8}}
(when (not= type :account) [text/text {:weight :semi-bold} (:name account-props)])
[rn/view
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
size
theme
blur?
container-style]}]
[rn/view {:style {:flex 1}}
container-style]
:or {container-style {:flex 1}}}]
[rn/view {:style container-style}
[quo/slide-button
{:size size
:container-style container-style
:customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize/authorize {:on-close on-close
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
(ns status-im.common.data-store.wallet
(ns status-im.contexts.wallet.data-store
(:require
[clojure.set :as set]
[clojure.string :as string]
[status-im.constants :as constants]
[utils.number :as utils.number]))
[clojure.set :as set]
[clojure.string :as string]
[status-im.constants :as constants]
[utils.number :as utils.number]))

(defn chain-ids-string->set
[ids-string]
Expand Down
2 changes: 1 addition & 1 deletion src/status_im/contexts/wallet/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[clojure.string :as string]
[quo.foundations.colors :as colors]
[react-native.background-timer :as background-timer]
[status-im.common.data-store.wallet :as data-store]
[status-im.contexts.wallet.data-store :as data-store]
[status-im.contexts.wallet.item-types :as item-types]
[status-im.contexts.wallet.temp :as temp]
[taoensso.timbre :as log]
Expand Down
214 changes: 143 additions & 71 deletions src/status_im/contexts/wallet/send/events.cljs
Original file line number Diff line number Diff line change
@@ -1,91 +1,163 @@
(ns status-im.contexts.wallet.send.events
(:require
[status-im.constants :as constants]
[taoensso.timbre :as log]
[utils.money :as money]
[utils.number]
[utils.re-frame :as rf]))
[camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]
[status-im.constants :as constants]
[status-im.contexts.wallet.send.utils :as send-utils]
[taoensso.timbre :as log]
[utils.money :as money]
[utils.number]
[utils.re-frame :as rf]))

(rf/reg-event-fx :wallet/select-address-tab
(fn [{:keys [db]} [tab]]
{:db (assoc-in db [:wallet :ui :send :select-address-tab] tab)}))
(fn [{:keys [db]} [tab]]

{:db (assoc-in db [:wallet :ui :send :select-address-tab] tab)}))

(rf/reg-event-fx :wallet/select-send-account-address
(fn [{:keys [db]} [address]]
{:db (assoc db [:wallet :ui :send :send-account-address] address)}))
(fn [{:keys [db]} [address]]
{:db (assoc db [:wallet :ui :send :send-account-address] address)}))

(rf/reg-event-fx :wallet/suggested-routes-success
(fn [{:keys [db]} [suggested-routes timestamp]]
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
{:db (-> db
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes)
(assoc-in [:wallet :ui :send :route] (first (:Best suggested-routes)))
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))})))
(fn [{:keys [db]} [suggested-routes timestamp]]
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
(let [suggested-routes-data (cske/transform-keys csk/->kebab-case suggested-routes)
chosen-route (->> suggested-routes-data
:best
first)]
{:db (-> db
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes-data)
(assoc-in [:wallet :ui :send :route] chosen-route)
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))))

(rf/reg-event-fx :wallet/suggested-routes-error
(fn [{:keys [db]} [_error]]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :suggested-routes)
(update-in [:wallet :ui :send] dissoc :route)
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))
(fn [{:keys [db]} [_error]]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :suggested-routes)
(update-in [:wallet :ui :send] dissoc :route)
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))

(rf/reg-event-fx :wallet/clean-suggested-routes
(fn [{:keys [db]}]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :suggested-routes)
(update-in [:wallet :ui :send] dissoc :route)
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
(fn [{:keys [db]}]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :suggested-routes)
(update-in [:wallet :ui :send] dissoc :route)
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))

(rf/reg-event-fx :wallet/select-send-address
(fn [{:keys [db]} [{:keys [address stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :to-address] address)
:fx [[:navigate-to-within-stack [:wallet-select-asset stack-id]]]}))
(fn [{:keys [db]} [{:keys [address stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :to-address] address)
:fx [[:navigate-to-within-stack [:wallet-select-asset stack-id]]]}))

(rf/reg-event-fx :wallet/send-select-token
(fn [{:keys [db]} [{:keys [token stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :token] token)
:fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]}))
(fn [{:keys [db]} [{:keys [token stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :token] token)
:fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]}))

(rf/reg-event-fx :wallet/send-select-amount
(fn [{:keys [db]} [{:keys [amount]}]]
(js/alert "Not implemented yet")
{:db (assoc-in db [:wallet :ui :send :amount] amount)}))
(fn [{:keys [db]} [{:keys [amount stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :amount] amount)
:fx [[:navigate-to-within-stack [:wallet-transaction-confirmation stack-id]]]}))

(rf/reg-event-fx :wallet/get-suggested-routes
(fn [{:keys [db now]} [amount]]
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
token (get-in db [:wallet :ui :send :token])
to-address (get-in db [:wallet :ui :send :to-address])
token-decimal (:decimals token)
token-id (:symbol token)
network-preferences []
gas-rates constants/gas-rate-medium
amount-in (money/amount-in-hex amount token-decimal)
from-address wallet-address
disabled-from-chain-ids []
disabled-to-chain-ids []
from-locked-amount {}
request-params [constants/send-type-transfer
from-address
to-address
amount-in
token-id
disabled-from-chain-ids
disabled-to-chain-ids
network-preferences
gas-rates
from-locked-amount]]
{:db (-> db
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true)
(assoc-in [:wallet :ui :send :suggested-routes-call-timestamp] now))
:json-rpc/call [{:method "wallet_getSuggestedRoutes"
:params request-params
:on-success (fn [suggested-routes]
(rf/dispatch [:wallet/suggested-routes-success suggested-routes
now]))
:on-error (fn [error]
(rf/dispatch [:wallet/suggested-routes-error error])
(log/error "failed to get suggested routes"
{:event :wallet/get-suggested-routes
:error error
:params request-params}))}]})))
(fn [{:keys [db now]} [amount]]
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
token (get-in db [:wallet :ui :send :token])
to-address (get-in db [:wallet :ui :send :to-address])
token-decimal (:decimals token)
token-id (:symbol token)
network-preferences []
gas-rates constants/gas-rate-medium
amount-in (send-utils/amount-in-hex amount token-decimal)
from-address wallet-address
disabled-from-chain-ids []
disabled-to-chain-ids []
from-locked-amount {}
request-params [constants/send-type-transfer
from-address
to-address
amount-in
token-id
disabled-from-chain-ids
disabled-to-chain-ids
network-preferences
gas-rates
from-locked-amount]]
{:db (-> db
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true)
(assoc-in [:wallet :ui :send :suggested-routes-call-timestamp] now))
:json-rpc/call [{:method "wallet_getSuggestedRoutes"
:params request-params
:on-success (fn [suggested-routes]
(rf/dispatch [:wallet/suggested-routes-success suggested-routes
now]))
:on-error (fn [error]
(rf/dispatch [:wallet/suggested-routes-error error])
(log/error "failed to get suggested routes"
{:event :wallet/get-suggested-routes
:error error
:params request-params}))}]})))

(rf/reg-event-fx :wallet/add-authorized-transaction
(fn [{:keys [db]} [transaction]]
(let [transaction-hashes (:hashes transaction)
chain-id (key (first transaction-hashes))
tx-id (first (val (first transaction-hashes)))
transaction-detes {:status :pending
:id (:id transaction)
:chain-id chain-id}]
{:db (assoc-in db [:wallet :transactions tx-id] transaction-detes)
:fx [[:dispatch [:navigate-to :wallet-transaction-progress]]]})))

(defn- transaction-bridge [{:keys [from-address to-address route]}]
(let [{:keys [from bridge-name amount-out gas-amount gas-fees]} route
{:keys [gas-price max-fee-per-gas-medium max-priority-fee-per-gas]} gas-fees]
[{:BridgeName bridge-name
:ChainID (:chain-id from)
:TransferTx {:From from-address
:To to-address
:Gas (money/to-hex gas-amount)
:GasPrice (money/to-hex (money/->wei :gwei gas-price))
:Value amount-out
:Nonce nil
:MaxFeePerGas (money/to-hex (money/->wei :gwei max-fee-per-gas-medium))
:MaxPriorityFeePerGas (money/to-hex (money/->wei :gwei max-priority-fee-per-gas))
:Input ""
:Data "0x"}}]))

(defn- multi-transaction-command [{:keys [from-address to-address from-asset to-asset amount-out transfer-type]
:or {transfer-type constants/send-type-transfer}}]
{:fromAddress from-address
:toAddress to-address
:fromAsset from-asset
:toAsset to-asset
:fromAmount amount-out
:type transfer-type})

(rf/reg-event-fx :wallet/send-transaction
(fn [{:keys [db]} [sha3-pwd]]
(let [route (get-in db [:wallet :ui :send :route])
from-address (get-in db [:wallet :current-viewing-account-address])
to-address (get-in db [:wallet :ui :send :to-address])
token (get-in db [:wallet :ui :send :token])
token-id (:symbol token)
request-params [(multi-transaction-command {:from-address from-address
:to-address to-address
:from-asset token-id
:to-asset token-id
:amount-out (:amount-out route)})
(transaction-bridge {:to-address to-address
:from-address from-address
:route route})
sha3-pwd]]
{:json-rpc/call [{:method "wallet_createMultiTransaction"
:params request-params
:on-success (fn [result]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet/add-authorized-transaction result]))
:on-error (fn [error]
(log/error "failed to send transaction"
{:event :wallet/send-transaction
:error error
:params request-params}))}]})))

Loading

0 comments on commit f612de3

Please sign in to comment.