Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a617599b0 |
@@ -211,7 +211,7 @@ android {
|
||||
reset()
|
||||
enable getEnvOrConfig('ANDROID_ABI_SPLIT').toBoolean()
|
||||
include getEnvOrConfig('ANDROID_ABI_INCLUDE').split(";")
|
||||
universalApk getEnvOrConfig('ORG_GRADLE_PROJECT_universalApk').toBoolean()
|
||||
universalApk false
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.9'
|
||||
library 'status-jenkins-lib@v1.9.8'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
# Android architectures to build for
|
||||
# Used to detect end-to-end builds
|
||||
androidAbiInclude ? lib.getEnvWithDefault "ANDROID_ABI_INCLUDE" "arm64-v8a",
|
||||
universalApk ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_universalApk" "false"
|
||||
}:
|
||||
|
||||
let
|
||||
@@ -90,7 +89,6 @@ in stdenv.mkDerivation rec {
|
||||
ORG_GRADLE_PROJECT_commitHash = commitHash;
|
||||
ORG_GRADLE_PROJECT_buildUrl = buildUrl;
|
||||
ORG_GRADLE_PROJECT_hermesEnabled = hermesEnabled;
|
||||
ORG_GRADLE_PROJECT_universalApk = universalApk;
|
||||
|
||||
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
|
||||
NODE_OPTIONS = "--openssl-legacy-provider";
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[:map {:closed true}
|
||||
[:action? {:optional true} [:maybe boolean?]]
|
||||
[:text {:optional true} [:maybe string?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:button-text {:optional true} [:maybe string?]]
|
||||
[:on-button-press {:optional true} [:maybe fn?]]]]]
|
||||
:any])
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
(ns quo.components.banners.alert-banner.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(defn container
|
||||
[container-style]
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 50
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 12}
|
||||
container-style))
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 50
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 12})
|
||||
|
||||
(defn label
|
||||
[theme]
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [action? text button-text container-style on-button-press]}]
|
||||
[{:keys [action? text button-text on-button-press]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view
|
||||
{:accessibility-label :alert-banner}
|
||||
[linear-gradient/linear-gradient
|
||||
{:style (style/container container-style)
|
||||
{:style style/container
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0 :y 1}
|
||||
:colors [(colors/theme-colors
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
[:subtitle-type {:optional true} [:maybe [:enum :default :icon :network :account :editable]]]
|
||||
[:size {:optional true} [:maybe [:enum :default :small :large]]]
|
||||
[:title :string]
|
||||
[:subtitle {:optional true} [:maybe [:or :string :double]]]
|
||||
[:subtitle {:optional true} [:maybe :string]]
|
||||
[:custom-subtitle {:optional true} [:maybe fn?]]
|
||||
[:icon {:optional true} [:maybe :keyword]]
|
||||
[:emoji {:optional true} [:maybe :string]]
|
||||
|
||||
@@ -60,12 +60,8 @@
|
||||
shrinkable? (assoc :flex-shrink 1)))
|
||||
|
||||
(defn text
|
||||
([theme]
|
||||
(text theme false))
|
||||
([theme gray-text?]
|
||||
{:color (if gray-text?
|
||||
colors/neutral-50
|
||||
(colors/theme-colors colors/neutral-100 colors/white theme))}))
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
|
||||
|
||||
(defn token-logo
|
||||
[size]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns quo.components.tags.context-tag.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.components.avatars.account-avatar.view :as account-avatar]
|
||||
[quo.components.avatars.group-avatar.view :as group-avatar]
|
||||
[quo.components.avatars.user-avatar.view :as user-avatar]
|
||||
@@ -18,16 +17,15 @@
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- tag-skeleton
|
||||
[{:keys [size text theme shrinkable? gray-text?]
|
||||
:or {size 24
|
||||
gray-text? false
|
||||
theme (quo.theme/use-theme)}}
|
||||
[{:keys [size text theme shrinkable?]
|
||||
:or {size 24
|
||||
theme (quo.theme/use-theme)}}
|
||||
logo-component]
|
||||
[rn/view {:style (style/tag-container size)}
|
||||
logo-component
|
||||
[rn/view {:style (style/tag-spacing size shrinkable?)}
|
||||
[text/text
|
||||
{:style (style/text theme gray-text?)
|
||||
{:style (style/text theme)
|
||||
:weight :medium
|
||||
:size (if (= size 24) :paragraph-2 :paragraph-1)
|
||||
:number-of-lines 1
|
||||
@@ -96,107 +94,92 @@
|
||||
state :default
|
||||
theme (quo.theme/use-theme)}
|
||||
:as props}]
|
||||
(let [[image-error? set-image-error] (rn/use-state false)]
|
||||
[rn/view {:style (merge {:align-items :flex-start} container-style)}
|
||||
[rn/view
|
||||
{:style (style/container {:theme theme
|
||||
:type type
|
||||
:size size
|
||||
:state state
|
||||
:blur? blur?
|
||||
:customization-color customization-color})
|
||||
:accessibility-label :context-tag}
|
||||
(case type
|
||||
:default
|
||||
[tag-skeleton {:theme theme :size size :text full-name}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name full-name
|
||||
:profile-picture profile-picture
|
||||
:size (if (= size 24) :xxs 28)
|
||||
:status-indicator? false
|
||||
:ring? false
|
||||
:customization-color customization-color}]]
|
||||
[rn/view {:style (merge {:align-items :flex-start} container-style)}
|
||||
[rn/view
|
||||
{:style (style/container {:theme theme
|
||||
:type type
|
||||
:size size
|
||||
:state state
|
||||
:blur? blur?
|
||||
:customization-color customization-color})
|
||||
:accessibility-label :context-tag}
|
||||
(case type
|
||||
:default
|
||||
[tag-skeleton {:theme theme :size size :text full-name}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name full-name
|
||||
:profile-picture profile-picture
|
||||
:size (if (= size 24) :xxs 28)
|
||||
:status-indicator? false
|
||||
:ring? false
|
||||
:customization-color customization-color}]]
|
||||
|
||||
:multiuser
|
||||
[preview-list/view {:type :user :size :size-20}
|
||||
users]
|
||||
:multiuser
|
||||
[preview-list/view {:type :user :size :size-20}
|
||||
users]
|
||||
|
||||
:multinetwork
|
||||
[preview-list/view {:type :network :size :size-20}
|
||||
networks]
|
||||
:multinetwork
|
||||
[preview-list/view {:type :network :size :size-20}
|
||||
networks]
|
||||
|
||||
:audio
|
||||
[tag-skeleton {:theme theme :text (str duration)}
|
||||
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
|
||||
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
|
||||
:audio
|
||||
[tag-skeleton {:theme theme :text (str duration)}
|
||||
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
|
||||
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
|
||||
|
||||
:group
|
||||
[tag-skeleton {:theme theme :size size :text group-name}
|
||||
[group-avatar/view
|
||||
{:icon-name :i/members
|
||||
:size (if (= size 24) :size-20 :size-28)
|
||||
:customization-color (colors/custom-color customization-color 50)}]]
|
||||
:group
|
||||
[tag-skeleton {:theme theme :size size :text group-name}
|
||||
[group-avatar/view
|
||||
{:icon-name :i/members
|
||||
:size (if (= size 24) :size-20 :size-28)
|
||||
:customization-color (colors/custom-color customization-color 50)}]]
|
||||
|
||||
(:channel :community)
|
||||
[communities-tag (assoc props :channel? (= type :channel))]
|
||||
(:channel :community)
|
||||
[communities-tag (assoc props :channel? (= type :channel))]
|
||||
|
||||
:token
|
||||
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
|
||||
[token/view
|
||||
{:style (style/token-logo size)
|
||||
:token token
|
||||
:size (if (= size 24) :size-20 :size-28)}]]
|
||||
:token
|
||||
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
|
||||
[token/view
|
||||
{:style (style/token-logo size)
|
||||
:token token
|
||||
:size (if (= size 24) :size-20 :size-28)}]]
|
||||
|
||||
:network
|
||||
[tag-skeleton {:theme theme :size size :text network-name}
|
||||
[rn/image {:style (style/circle-logo size) :source network-logo}]]
|
||||
:network
|
||||
[tag-skeleton {:theme theme :size size :text network-name}
|
||||
[rn/image {:style (style/circle-logo size) :source network-logo}]]
|
||||
|
||||
:collectible
|
||||
(let [gray-text? (string/blank? collectible-name)
|
||||
collectible-text (cond
|
||||
gray-text? "UNKNOWN"
|
||||
collectible-number (str collectible-name
|
||||
" #"
|
||||
collectible-number)
|
||||
:else collectible-name)
|
||||
nft-placeholder? (or image-error? (string/blank? collectible))]
|
||||
[tag-skeleton
|
||||
{:theme theme
|
||||
:size size
|
||||
:text collectible-text
|
||||
:shrinkable? true
|
||||
:gray-text? gray-text?}
|
||||
(if nft-placeholder?
|
||||
[icons/icon :i/nft {:size 20}]
|
||||
[rn/image
|
||||
{:style (style/rounded-logo size)
|
||||
:source collectible
|
||||
:on-error #(set-image-error true)}])])
|
||||
:collectible
|
||||
[tag-skeleton
|
||||
{:theme theme
|
||||
:size size
|
||||
:text (str collectible-name " #" collectible-number)
|
||||
:shrinkable? true}
|
||||
[rn/image {:style (style/rounded-logo size) :source collectible}]]
|
||||
|
||||
:account
|
||||
[tag-skeleton {:theme theme :size size :text account-name}
|
||||
[account-avatar/view
|
||||
{:customization-color customization-color
|
||||
:emoji emoji
|
||||
:size (if (= size 24) 20 28)}]]
|
||||
:account
|
||||
[tag-skeleton {:theme theme :size size :text account-name}
|
||||
[account-avatar/view
|
||||
{:customization-color customization-color
|
||||
:emoji emoji
|
||||
:size (if (= size 24) 20 28)}]]
|
||||
|
||||
:address
|
||||
[address-tag props]
|
||||
:address
|
||||
[address-tag props]
|
||||
|
||||
:icon
|
||||
[icon-tag props]
|
||||
:icon
|
||||
[icon-tag props]
|
||||
|
||||
:wallet-user
|
||||
[tag-skeleton {:theme theme :size size :text full-name}
|
||||
[wallet-user-avatar/wallet-user-avatar
|
||||
{:full-name full-name
|
||||
:size (if (= size 24) :size-20 :size-24)
|
||||
:customization-color customization-color}]]
|
||||
:wallet-user
|
||||
[tag-skeleton {:theme theme :size size :text full-name}
|
||||
[wallet-user-avatar/wallet-user-avatar
|
||||
{:full-name full-name
|
||||
:size (if (= size 24) :size-20 :size-24)
|
||||
:customization-color customization-color}]]
|
||||
|
||||
:dapp
|
||||
[tag-skeleton {:theme theme :size size :text dapp-name}
|
||||
[rn/image {:style (style/circle-logo size) :source dapp-logo}]]
|
||||
:dapp
|
||||
[tag-skeleton {:theme theme :size size :text dapp-name}
|
||||
[rn/image {:style (style/circle-logo size) :source dapp-logo}]]
|
||||
|
||||
nil)]]))
|
||||
nil)]])
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
[:token-value :string]
|
||||
[:token-symbol :string]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:show-view-button? {:optional true} [:maybe :boolean]]
|
||||
[:button-props {:optional true} [:maybe :map]]
|
||||
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]]]]
|
||||
:any])
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [status token-value token-symbol
|
||||
container-style button-props show-view-button?]
|
||||
container-style button-props]
|
||||
:as props}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
customization-color (or (:customization-color props) :blue)
|
||||
@@ -56,9 +56,7 @@
|
||||
(i18n/label (status-message status)
|
||||
{:amount token-value
|
||||
:symbol token-symbol})]]
|
||||
(when (and button-props
|
||||
(or (= status :approve)
|
||||
(and (not= status :approve) show-view-button?)))
|
||||
(when button-props
|
||||
[button/button
|
||||
(merge {:type (if (= status :approve) :primary :grey)
|
||||
:background (when-not (= status :approve) :blur)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns quo.components.wallet.swap-input.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[quo.foundations.shadows :as shadows]
|
||||
[quo.foundations.typography :as typography]))
|
||||
|
||||
(defn- border-color
|
||||
@@ -12,13 +11,11 @@
|
||||
(colors/theme-colors colors/neutral-5 colors/neutral-90 theme))
|
||||
|
||||
(defn content
|
||||
[typing? theme]
|
||||
(merge
|
||||
{:border-width 1
|
||||
:border-radius 16
|
||||
:border-color (border-color theme)
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}
|
||||
(when typing? (shadows/get 1 theme))))
|
||||
[theme]
|
||||
{:border-width 1
|
||||
:border-radius 16
|
||||
:border-color (border-color theme)
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
|
||||
|
||||
(defn row-1
|
||||
[loading?]
|
||||
|
||||
@@ -19,15 +19,13 @@
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:type {:optional true} [:maybe [:enum :pay :receive]]]
|
||||
[:status {:optional true} [:maybe [:enum :default :typing :disabled :loading]]]
|
||||
[:status {:optional true} [:maybe [:enum :default :disabled :loading]]]
|
||||
[:token {:optional true} [:maybe :string]]
|
||||
[:value {:optional true} [:maybe :string]]
|
||||
[:default-value {:optional true} [:maybe :string]]
|
||||
[:currency-symbol {:optional true} [:maybe :string]]
|
||||
[:fiat-value {:optional true} [:maybe :string]]
|
||||
[:show-approval-label? {:optional true} [:maybe :boolean]]
|
||||
[:auto-focus? {:optional true} [:maybe :boolean]]
|
||||
[:input-disabled? {:optional true} [:maybe :boolean]]
|
||||
[:error? {:optional true} [:maybe :boolean]]
|
||||
[:show-keyboard? {:optional true} [:maybe :boolean]]
|
||||
[:approval-label-props {:optional true} [:maybe approval-label.schema/?schema]]
|
||||
@@ -35,7 +33,6 @@
|
||||
[:on-change-text {:optional true} [:maybe fn?]]
|
||||
[:enable-swap? {:optional true} [:maybe :boolean]]
|
||||
[:on-swap-press {:optional true} [:maybe fn?]]
|
||||
[:on-input-focus {:optional true} [:maybe fn?]]
|
||||
[:on-token-press {:optional true} [:maybe fn?]]
|
||||
[:on-max-press {:optional true} [:maybe fn?]]
|
||||
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
|
||||
@@ -44,14 +41,13 @@
|
||||
|
||||
(defn view-internal
|
||||
[{:keys [type status token value fiat-value show-approval-label? error? network-tag-props
|
||||
approval-label-props default-value auto-focus? input-disabled? enable-swap?
|
||||
approval-label-props default-value enable-swap?
|
||||
currency-symbol on-change-text show-keyboard?
|
||||
container-style on-swap-press on-token-press on-max-press on-input-focus]}]
|
||||
container-style on-swap-press on-token-press on-max-press]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
pay? (= type :pay)
|
||||
disabled? (= status :disabled)
|
||||
loading? (= status :loading)
|
||||
typing? (= status :typing)
|
||||
controlled-input? (some? value)
|
||||
input-ref (rn/use-ref-atom nil)
|
||||
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)) [])
|
||||
@@ -62,7 +58,7 @@
|
||||
[rn/view
|
||||
{:style container-style
|
||||
:accessibility-label :swap-input}
|
||||
[rn/view {:style (style/content typing? theme)}
|
||||
[rn/view {:style (style/content theme)}
|
||||
[rn/view
|
||||
{:style (style/row-1 loading?)}
|
||||
[rn/pressable {:on-press on-token-press}
|
||||
@@ -82,9 +78,7 @@
|
||||
colors/neutral-50
|
||||
theme)
|
||||
:keyboard-type :numeric
|
||||
:editable (not input-disabled?)
|
||||
:auto-focus auto-focus?
|
||||
:on-focus on-input-focus
|
||||
:auto-focus true
|
||||
:on-change-text on-change-text
|
||||
:show-soft-input-on-focus show-keyboard?
|
||||
:default-value default-value
|
||||
|
||||
@@ -551,7 +551,6 @@
|
||||
(def ^:const send-type-bridge 5)
|
||||
(def ^:const send-type-erc-721-transfer 6)
|
||||
(def ^:const send-type-erc-1155-transfer 7)
|
||||
(def ^:const send-type-swap 8)
|
||||
|
||||
(def ^:const multi-transaction-type-send 0)
|
||||
(def ^:const multi-transaction-type-approve 1)
|
||||
@@ -565,7 +564,6 @@
|
||||
(def ^:const bridge-name-erc-721-transfer "ERC721Transfer")
|
||||
(def ^:const bridge-name-erc-1155-transfer "ERC1155Transfer")
|
||||
(def ^:const bridge-name-hop "Hop")
|
||||
(def ^:const bridge-name-paraswap "Paraswap")
|
||||
|
||||
(def ^:const bridge-assets #{"ETH" "USDT" "USDC" "DAI"})
|
||||
|
||||
@@ -592,19 +590,9 @@
|
||||
(def ^:const default-slippage 0.5)
|
||||
(def ^:const max-recommended-slippage 5)
|
||||
(def ^:const max-slippage-decimal-places 2)
|
||||
(def ^:const swap-provider-paraswap
|
||||
(def ^:const swap-default-provider
|
||||
{:name :paraswap
|
||||
:full-name "Paraswap"
|
||||
:color :blue
|
||||
:contract-address "0xdef171fe48cf0115b1d80b88dc8eab59176fee57"
|
||||
:terms-and-conditions-url "https://files.paraswap.io/tos_v4.pdf"})
|
||||
(def ^:const swap-providers
|
||||
{:paraswap swap-provider-paraswap})
|
||||
|
||||
(def ^:const token-for-fees-symbol "ETH")
|
||||
|
||||
(def ^:const transaction-status-success "Success")
|
||||
(def ^:const transaction-status-pending "Pending")
|
||||
(def ^:const transaction-status-failed "Failed")
|
||||
|
||||
(def ^:const min-token-decimals-to-display 6)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.check-before-syncing.view :as check-before-syncing]
|
||||
[status-im.common.confirmation-drawer.view :as confirmation-drawer]
|
||||
[status-im.common.metrics-confirmation-modal.view :as metrics-modal]
|
||||
[status-im.common.standard-authentication.core :as standard-authentication]
|
||||
@@ -43,32 +44,32 @@
|
||||
:linear
|
||||
50))
|
||||
|
||||
(defn- navigate-to-new-to-status
|
||||
(defn- show-check-before-syncing
|
||||
[]
|
||||
(when @push-animation-fn-atom
|
||||
(@push-animation-fn-atom))
|
||||
(debounce/throttle-and-dispatch
|
||||
[:open-modal :screen/onboarding.new-to-status]
|
||||
1000))
|
||||
|
||||
(defn- navigate-to-sync-or-recover-profile
|
||||
[]
|
||||
(when @push-animation-fn-atom
|
||||
(@push-animation-fn-atom))
|
||||
(debounce/throttle-and-dispatch
|
||||
[:open-modal :screen/onboarding.sync-or-recover-profile]
|
||||
1000))
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn [] [check-before-syncing/view
|
||||
{:on-submit
|
||||
#(debounce/throttle-and-dispatch
|
||||
[:open-modal :screen/onboarding.sign-in]
|
||||
1000)}])
|
||||
:shell? true}]))
|
||||
|
||||
(defn new-account-options
|
||||
[]
|
||||
[quo/action-drawer
|
||||
[[{:icon :i/profile
|
||||
:label (i18n/label :t/create-new-profile)
|
||||
:on-press navigate-to-new-to-status
|
||||
:on-press (fn []
|
||||
(when @push-animation-fn-atom
|
||||
(@push-animation-fn-atom))
|
||||
(debounce/throttle-and-dispatch
|
||||
[:open-modal :screen/onboarding.new-to-status]
|
||||
1000))
|
||||
:accessibility-label :create-new-profile}
|
||||
{:icon :i/multi-profile
|
||||
:label (i18n/label :t/sync-or-recover-profile)
|
||||
:on-press navigate-to-sync-or-recover-profile
|
||||
:label (i18n/label :t/add-existing-status-profile)
|
||||
:on-press show-check-before-syncing
|
||||
:accessibility-label :multi-profile}]]])
|
||||
|
||||
(defn show-new-account-options
|
||||
|
||||
@@ -9,45 +9,25 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- mention-text
|
||||
[literal]
|
||||
(let [mention (rf/sub [:messages/resolve-mention literal])]
|
||||
[quo/text
|
||||
{:style style/mention-text
|
||||
:size :paragraph-1}
|
||||
(str "@" mention)]))
|
||||
|
||||
(defn- parsed-text->hiccup
|
||||
[{:keys [literal destination] message-type :type}]
|
||||
(case message-type
|
||||
"mention" [mention-text literal]
|
||||
"link" destination
|
||||
literal))
|
||||
|
||||
(defn- message-body
|
||||
[{:keys [container parsed-text]}]
|
||||
(into container (map parsed-text->hiccup) parsed-text))
|
||||
|
||||
(defn- simple-message
|
||||
[content]
|
||||
(let [parsed-text (get-in content [:content :parsed-text 0 :children])]
|
||||
[message-body
|
||||
{:container [quo/text
|
||||
{:number-of-lines 1
|
||||
:style style/tag-text
|
||||
:accessibility-label :activity-message-body
|
||||
:size :paragraph-1}]
|
||||
:parsed-text parsed-text}]))
|
||||
|
||||
(defn- album-message
|
||||
[content]
|
||||
(let [parsed-text (get-in content [0 :parsedText 0 :children])
|
||||
images (map :image content)]
|
||||
[quo/activity-logs-photos
|
||||
{:photos images
|
||||
:message-text [message-body
|
||||
{:container [:<>]
|
||||
:parsed-text parsed-text}]}]))
|
||||
[message]
|
||||
(let [parsed-text (get-in message [:content :parsed-text])
|
||||
parsed-text-children (:children (first parsed-text))]
|
||||
(into [quo/text
|
||||
{:number-of-lines 1
|
||||
:style style/tag-text
|
||||
:accessibility-label :activity-message-body
|
||||
:size :paragraph-1}]
|
||||
(map-indexed (fn [index {:keys [type literal destination]}]
|
||||
^{:key index}
|
||||
(case type
|
||||
"mention" [quo/text
|
||||
{:style style/mention-text
|
||||
:size :paragraph-1}
|
||||
(str "@" (rf/sub [:messages/resolve-mention literal]))]
|
||||
"link" destination
|
||||
literal))
|
||||
parsed-text-children))))
|
||||
|
||||
(defn- swipeable
|
||||
[{:keys [extra-fn]} child]
|
||||
@@ -61,12 +41,12 @@
|
||||
|
||||
(defn view
|
||||
[{:keys [notification extra-fn]}]
|
||||
(let [{:keys [author chat-name community-id chat-id message read timestamp
|
||||
album-messages]} notification
|
||||
community-chat? (not (string/blank? community-id))
|
||||
community-name (rf/sub [:communities/name community-id])
|
||||
community-logo (rf/sub [:communities/logo community-id])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
(let [{:keys [author chat-name community-id chat-id
|
||||
message read timestamp]} notification
|
||||
community-chat? (not (string/blank? community-id))
|
||||
community-name (rf/sub [:communities/name community-id])
|
||||
community-logo (rf/sub [:communities/logo community-id])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[swipeable {:extra-fn extra-fn}
|
||||
[gesture/touchable-without-feedback
|
||||
{:on-press (fn []
|
||||
@@ -94,6 +74,4 @@
|
||||
:group-name chat-name
|
||||
:blur? true
|
||||
:size 24}])]
|
||||
:message {:body (if album-messages
|
||||
[album-message album-messages]
|
||||
[simple-message message])}}]]]))
|
||||
:message {:body (message-body message)}}]]]))
|
||||
|
||||
@@ -24,32 +24,35 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn notification-component
|
||||
[{notification-type :type :as notification} index]
|
||||
[{:keys [type] :as notification} index]
|
||||
(let [extra-fn (rn/use-callback
|
||||
(fn []
|
||||
{:notification notification})
|
||||
[notification])
|
||||
props {:notification notification
|
||||
:extra-fn extra-fn}]
|
||||
;; Notifications are expensive to render. Without `delay-render` the opening
|
||||
;; animation of the Activity Center can be clunky and the time to open the
|
||||
;; AC after pressing the bell icon can be high.
|
||||
[rn/view {:style (style/notification-container index)}
|
||||
(cond
|
||||
(= notification-type types/contact-verification)
|
||||
(= type types/contact-verification)
|
||||
[contact-verification/view props]
|
||||
|
||||
(= notification-type types/contact-request)
|
||||
(= type types/contact-request)
|
||||
[contact-requests/view props]
|
||||
|
||||
(= notification-type types/mention)
|
||||
(= type types/mention)
|
||||
[mentions/view props]
|
||||
|
||||
(= notification-type types/reply)
|
||||
(= type types/reply)
|
||||
[reply/view props]
|
||||
|
||||
(= notification-type types/admin)
|
||||
(= type types/admin)
|
||||
[admin/view props]
|
||||
|
||||
(types/membership notification-type)
|
||||
(condp = notification-type
|
||||
(some types/membership [type])
|
||||
(condp = type
|
||||
types/private-group-chat [membership/view props]
|
||||
types/community-request [community-request/view props]
|
||||
types/community-kicked [community-kicked/view props]
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
:collectible-name (if (> amount 1)
|
||||
(str amount " " nft-name)
|
||||
nft-name)
|
||||
:collectible-number (when (not= token-id "0")
|
||||
token-id)}
|
||||
:collectible-number token-id}
|
||||
:second-tag-prefix :t/from
|
||||
:second-tag {:type :address :address sender}
|
||||
:third-tag-prefix :t/to
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
(ns status-im.contexts.wallet.common.utils
|
||||
(:require [clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.foundations.resources :as resources]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.constants :as constants]
|
||||
[utils.hex :as utils.hex]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]
|
||||
[utils.string]))
|
||||
@@ -350,131 +348,3 @@
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt (comp - :balance) priority) tokens)))
|
||||
|
||||
(defn- transaction-data
|
||||
[{:keys [from-address to-address token-address route data eth-transfer?]}]
|
||||
(let [{:keys [amount-in gas-amount gas-fees]} route
|
||||
eip-1559-enabled? (:eip-1559-enabled gas-fees)
|
||||
{:keys [gas-price max-fee-per-gas-medium
|
||||
max-priority-fee-per-gas]} gas-fees]
|
||||
(cond-> {:From from-address
|
||||
:To (or token-address to-address)
|
||||
:Gas (money/to-hex gas-amount)
|
||||
:Value (when eth-transfer? amount-in)
|
||||
:Nonce nil
|
||||
:Input ""
|
||||
:Data (or data "0x")}
|
||||
eip-1559-enabled? (assoc
|
||||
:TxType "0x02"
|
||||
:MaxFeePerGas
|
||||
(money/to-hex
|
||||
(money/->wei
|
||||
:gwei
|
||||
max-fee-per-gas-medium))
|
||||
:MaxPriorityFeePerGas
|
||||
(money/to-hex
|
||||
(money/->wei
|
||||
:gwei
|
||||
max-priority-fee-per-gas)))
|
||||
(not eip-1559-enabled?) (assoc :TxType "0x00"
|
||||
:GasPrice
|
||||
(money/to-hex
|
||||
(money/->wei
|
||||
:gwei
|
||||
gas-price))))))
|
||||
|
||||
(defn approval-path
|
||||
[{:keys [route from-address to-address token-address]}]
|
||||
(let [{:keys [from]} route
|
||||
from-chain-id (:chain-id from)
|
||||
approval-amount-required (:approval-amount-required route)
|
||||
approval-amount-required-sanitized (-> approval-amount-required
|
||||
(utils.hex/normalize-hex)
|
||||
(native-module/hex-to-number))
|
||||
approval-contract-address (:approval-contract-address route)
|
||||
data (native-module/encode-function-call
|
||||
constants/contract-function-signature-erc20-approve
|
||||
[approval-contract-address
|
||||
approval-amount-required-sanitized])
|
||||
tx-data (transaction-data {:from-address from-address
|
||||
:to-address to-address
|
||||
:token-address token-address
|
||||
:route route
|
||||
:data data
|
||||
:eth-transfer? false})]
|
||||
{:BridgeName constants/bridge-name-transfer
|
||||
:ChainID from-chain-id
|
||||
:TransferTx tx-data}))
|
||||
|
||||
(defn transaction-path
|
||||
[{:keys [from-address to-address token-id-from token-address token-id-to route data
|
||||
slippage-percentage eth-transfer?]}]
|
||||
(let [{:keys [bridge-name amount-in bonder-fees from
|
||||
to]} route
|
||||
tx-data (transaction-data {:from-address from-address
|
||||
:to-address to-address
|
||||
:token-address token-address
|
||||
:route route
|
||||
:data data
|
||||
:eth-transfer? eth-transfer?})
|
||||
to-chain-id (:chain-id to)
|
||||
from-chain-id (:chain-id from)]
|
||||
(cond-> {:BridgeName bridge-name
|
||||
:ChainID from-chain-id}
|
||||
|
||||
(= bridge-name constants/bridge-name-erc-721-transfer)
|
||||
(assoc :ERC721TransferTx
|
||||
(assoc tx-data
|
||||
:Recipient to-address
|
||||
:TokenID token-id-from
|
||||
:ChainID to-chain-id))
|
||||
|
||||
(= bridge-name constants/bridge-name-erc-1155-transfer)
|
||||
(assoc :ERC1155TransferTx
|
||||
(assoc tx-data
|
||||
:Recipient to-address
|
||||
:TokenID token-id-from
|
||||
:ChainID to-chain-id
|
||||
:Amount amount-in))
|
||||
|
||||
(= bridge-name constants/bridge-name-transfer)
|
||||
(assoc :TransferTx tx-data)
|
||||
|
||||
(= bridge-name constants/bridge-name-hop)
|
||||
(assoc :HopTx
|
||||
(assoc tx-data
|
||||
:ChainID from-chain-id
|
||||
:ChainIDTo to-chain-id
|
||||
:Symbol token-id-from
|
||||
:Recipient to-address
|
||||
:Amount amount-in
|
||||
:BonderFee bonder-fees))
|
||||
|
||||
(= bridge-name constants/bridge-name-paraswap)
|
||||
(assoc :SwapTx
|
||||
(assoc tx-data
|
||||
:ChainID from-chain-id
|
||||
:ChainIDTo to-chain-id
|
||||
:TokenIDFrom token-id-from
|
||||
:TokenIDTo token-id-to
|
||||
:SlippagePercentage slippage-percentage))
|
||||
|
||||
(not (or (= bridge-name constants/bridge-name-erc-721-transfer)
|
||||
(= bridge-name constants/bridge-name-transfer)
|
||||
(= bridge-name constants/bridge-name-hop)))
|
||||
(assoc :CbridgeTx
|
||||
(assoc tx-data
|
||||
:ChainID to-chain-id
|
||||
:Symbol token-id-from
|
||||
:Recipient to-address
|
||||
:Amount amount-in)))))
|
||||
|
||||
(defn multi-transaction-command
|
||||
[{:keys [from-address to-address from-asset to-asset amount-out multi-transaction-type]
|
||||
:or {multi-transaction-type constants/multi-transaction-type-unknown}}]
|
||||
{:fromAddress from-address
|
||||
:toAddress to-address
|
||||
:fromAsset from-asset
|
||||
:toAsset to-asset
|
||||
:fromAmount amount-out
|
||||
:type multi-transaction-type})
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.hex :as utils.hex]
|
||||
[utils.money :as utils.money]
|
||||
[utils.money :as money]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -518,29 +518,23 @@
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/handle-suggested-routes
|
||||
(fn [{:keys [db]} [data]]
|
||||
(let [swap? (get-in db [:wallet :ui :swap])
|
||||
{:keys [code details] :as error-response} (-> data :ErrorResponse)]
|
||||
(if (and (not swap?) error-response)
|
||||
(let [error-message (if (= code "0") "An error occurred" details)]
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/handle-suggested-routes
|
||||
:error error-message})
|
||||
{:fx [(if swap?
|
||||
[:dispatch [:wallet/swap-proposal-error error-message]]
|
||||
[:dispatch [:wallet/suggested-routes-error error-message]])]})
|
||||
(let [best-routes-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes
|
||||
remove-multichain-routes)
|
||||
candidates-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes)
|
||||
routes (-> data
|
||||
(data-store/rpc->suggested-routes)
|
||||
(update :best best-routes-fix)
|
||||
(update :candidates candidates-fix))]
|
||||
{:fx [(if swap?
|
||||
[:dispatch [:wallet/swap-proposal-success routes]]
|
||||
[:dispatch [:wallet/suggested-routes-success routes]])]})))))
|
||||
(fn [_ [data]]
|
||||
(if-let [{:keys [code details]} (-> data :ErrorResponse)]
|
||||
(let [error-message (if (= code "0") "An error occurred" details)]
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/handle-suggested-routes
|
||||
:error error-message})
|
||||
{:fx [[:dispatch [:wallet/suggested-routes-error error-message]]]})
|
||||
(let [best-routes-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes
|
||||
remove-multichain-routes)
|
||||
candidates-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes)
|
||||
routes (-> data
|
||||
(data-store/rpc->suggested-routes)
|
||||
(update :best best-routes-fix)
|
||||
(update :candidates candidates-fix))]
|
||||
{:fx [[:dispatch [:wallet/suggested-routes-success routes]]]}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/add-authorized-transaction
|
||||
(fn [{:keys [db]} [transaction]]
|
||||
@@ -582,6 +576,124 @@
|
||||
[{:ms 20
|
||||
:dispatch [:wallet/clean-up-transaction-flow]}]]]})))
|
||||
|
||||
(defn- transaction-data
|
||||
[{:keys [from-address to-address token-address route data eth-transfer?]}]
|
||||
(let [{:keys [amount-in gas-amount gas-fees]} route
|
||||
eip-1559-enabled? (:eip-1559-enabled gas-fees)
|
||||
{:keys [gas-price max-fee-per-gas-medium
|
||||
max-priority-fee-per-gas]} gas-fees]
|
||||
(cond-> {:From from-address
|
||||
:To (or token-address to-address)
|
||||
:Gas (money/to-hex gas-amount)
|
||||
:Value (when eth-transfer? amount-in)
|
||||
:Nonce nil
|
||||
:Input ""
|
||||
:Data (or data "0x")}
|
||||
eip-1559-enabled? (assoc
|
||||
:TxType "0x02"
|
||||
:MaxFeePerGas
|
||||
(money/to-hex
|
||||
(money/->wei
|
||||
:gwei
|
||||
max-fee-per-gas-medium))
|
||||
:MaxPriorityFeePerGas
|
||||
(money/to-hex
|
||||
(money/->wei
|
||||
:gwei
|
||||
max-priority-fee-per-gas)))
|
||||
(not eip-1559-enabled?) (assoc :TxType "0x00"
|
||||
:GasPrice
|
||||
(money/to-hex
|
||||
(money/->wei
|
||||
:gwei
|
||||
gas-price))))))
|
||||
|
||||
(defn- approval-path
|
||||
[{:keys [route from-address to-address token-address]}]
|
||||
(let [{:keys [from]} route
|
||||
from-chain-id (:chain-id from)
|
||||
approval-amount-required (:approval-amount-required route)
|
||||
approval-amount-required-sanitized (-> approval-amount-required
|
||||
(utils.hex/normalize-hex)
|
||||
(native-module/hex-to-number))
|
||||
approval-contract-address (:approval-contract-address route)
|
||||
data (native-module/encode-function-call
|
||||
constants/contract-function-signature-erc20-approve
|
||||
[approval-contract-address
|
||||
approval-amount-required-sanitized])
|
||||
tx-data (transaction-data {:from-address from-address
|
||||
:to-address to-address
|
||||
:token-address token-address
|
||||
:route route
|
||||
:data data
|
||||
:eth-transfer? false})]
|
||||
{:BridgeName constants/bridge-name-transfer
|
||||
:ChainID from-chain-id
|
||||
:TransferTx tx-data}))
|
||||
|
||||
(defn- transaction-path
|
||||
[{:keys [from-address to-address token-id token-address route data eth-transfer?]}]
|
||||
(let [{:keys [bridge-name amount-in bonder-fees from
|
||||
to]} route
|
||||
tx-data (transaction-data {:from-address from-address
|
||||
:to-address to-address
|
||||
:token-address token-address
|
||||
:route route
|
||||
:data data
|
||||
:eth-transfer? eth-transfer?})
|
||||
to-chain-id (:chain-id to)
|
||||
from-chain-id (:chain-id from)]
|
||||
(cond-> {:BridgeName bridge-name
|
||||
:ChainID from-chain-id}
|
||||
|
||||
(= bridge-name constants/bridge-name-erc-721-transfer)
|
||||
(assoc :ERC721TransferTx
|
||||
(assoc tx-data
|
||||
:Recipient to-address
|
||||
:TokenID token-id
|
||||
:ChainID to-chain-id))
|
||||
|
||||
(= bridge-name constants/bridge-name-erc-1155-transfer)
|
||||
(assoc :ERC1155TransferTx
|
||||
(assoc tx-data
|
||||
:Recipient to-address
|
||||
:TokenID token-id
|
||||
:ChainID to-chain-id
|
||||
:Amount amount-in))
|
||||
|
||||
(= bridge-name constants/bridge-name-transfer)
|
||||
(assoc :TransferTx tx-data)
|
||||
|
||||
(= bridge-name constants/bridge-name-hop)
|
||||
(assoc :HopTx
|
||||
(assoc tx-data
|
||||
:ChainID from-chain-id
|
||||
:ChainIDTo to-chain-id
|
||||
:Symbol token-id
|
||||
:Recipient to-address
|
||||
:Amount amount-in
|
||||
:BonderFee bonder-fees))
|
||||
|
||||
(not (or (= bridge-name constants/bridge-name-erc-721-transfer)
|
||||
(= bridge-name constants/bridge-name-transfer)
|
||||
(= bridge-name constants/bridge-name-hop)))
|
||||
(assoc :CbridgeTx
|
||||
(assoc tx-data
|
||||
:ChainID to-chain-id
|
||||
:Symbol token-id
|
||||
:Recipient to-address
|
||||
:Amount amount-in)))))
|
||||
|
||||
(defn- multi-transaction-command
|
||||
[{:keys [from-address to-address from-asset to-asset amount-out multi-transaction-type]
|
||||
:or {multi-transaction-type constants/multi-transaction-type-unknown}}]
|
||||
{:fromAddress from-address
|
||||
:toAddress to-address
|
||||
:fromAsset from-asset
|
||||
:toAsset to-asset
|
||||
:fromAmount amount-out
|
||||
:type multi-transaction-type})
|
||||
|
||||
(rf/reg-event-fx :wallet/send-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [routes (get-in db [:wallet :ui :send :route])
|
||||
@@ -613,27 +725,27 @@
|
||||
(native-module/encode-transfer
|
||||
(address/normalized-hex to-address)
|
||||
(:amount-in route)))
|
||||
base-path (utils/transaction-path
|
||||
base-path (transaction-path
|
||||
{:to-address to-address
|
||||
:from-address from-address
|
||||
:route route
|
||||
:token-address token-address
|
||||
:token-id-from (if collectible
|
||||
:token-id (if collectible
|
||||
(utils.hex/number-to-hex
|
||||
token-id)
|
||||
token-id)
|
||||
:data data
|
||||
:eth-transfer? eth-transfer?})]
|
||||
(if approval-required?
|
||||
[(utils/approval-path {:route route
|
||||
:token-address token-address
|
||||
:from-address from-address
|
||||
:to-address to-address})
|
||||
[(approval-path {:route route
|
||||
:token-address token-address
|
||||
:from-address from-address
|
||||
:to-address to-address})
|
||||
base-path]
|
||||
[base-path]))))
|
||||
routes)
|
||||
request-params
|
||||
[(utils/multi-transaction-command
|
||||
[(multi-transaction-command
|
||||
{:from-address from-address
|
||||
:to-address to-address
|
||||
:from-asset token-id
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.contexts.wallet.signals
|
||||
(:require
|
||||
[oops.core :as oops]
|
||||
[status-im.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as transforms]))
|
||||
@@ -9,33 +8,9 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/pending-transaction-status-changed-received
|
||||
(fn [{:keys [db]} [{:keys [message]}]]
|
||||
(let [details (transforms/json->clj message)
|
||||
tx-hash (:hash details)
|
||||
tx-status (:status details)
|
||||
status (cond
|
||||
(= tx-status constants/transaction-status-success)
|
||||
:confirmed
|
||||
(= tx-status constants/transaction-status-pending)
|
||||
:pending
|
||||
(= tx-status constants/transaction-status-failed)
|
||||
:failed)
|
||||
swap-approval-transaction-id (get-in db [:wallet :ui :swap :approval-transaction-id])
|
||||
swap-approval-transaction? (= swap-approval-transaction-id tx-hash)
|
||||
swap-transaction-ids (get-in db [:wallet :swap-transaction-ids])
|
||||
swap-transaction? (and swap-transaction-ids
|
||||
(contains? swap-transaction-ids tx-hash))]
|
||||
(cond-> {:db (update-in db [:wallet :transactions tx-hash] assoc :status status)}
|
||||
swap-approval-transaction?
|
||||
(assoc :fx
|
||||
[[:dispatch
|
||||
[:wallet.swap/approve-transaction-update
|
||||
{:status status}]]])
|
||||
swap-transaction?
|
||||
(assoc :fx
|
||||
[[:dispatch
|
||||
[:wallet.swap/swap-transaction-update
|
||||
{:tx-hash tx-hash
|
||||
:status status}]]])))))
|
||||
(let [details (transforms/json->clj message)
|
||||
tx-hash (:hash details)]
|
||||
{:db (update-in db [:wallet :transactions tx-hash] assoc :status :confirmed :blocks 1)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/signal-received
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
(ns status-im.contexts.wallet.swap.events
|
||||
(:require [native-module.core :as native-module]
|
||||
[re-frame.core :as rf]
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.contexts.wallet.sheets.network-selection.view :as network-selection]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.hex :as hex]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.number]
|
||||
[utils.number :as number]))
|
||||
[utils.number]))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/start
|
||||
(fn [{:keys [_db]}]
|
||||
@@ -23,9 +14,7 @@
|
||||
(assoc-in [:wallet :ui :swap :asset-to-pay] token)
|
||||
(assoc-in [:wallet :ui :swap :network] network))
|
||||
:fx (if network
|
||||
[[:dispatch
|
||||
[:navigate-to-within-stack
|
||||
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]]]
|
||||
[[:dispatch [:navigate-to :screen/wallet.swap-propasal]]
|
||||
[:dispatch [:wallet.swap/set-default-slippage]]]
|
||||
[[:dispatch
|
||||
[:show-bottom-sheet
|
||||
@@ -41,6 +30,10 @@
|
||||
:stack-id
|
||||
:screen/wallet.swap-select-asset-to-pay}]))}])}]]])}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/clean-asset-to-pay
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :swap] dissoc :asset-to-pay)}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/set-default-slippage
|
||||
(fn [{:keys [db]}]
|
||||
{:db
|
||||
@@ -54,313 +47,18 @@
|
||||
(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?)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/start-get-swap-proposal
|
||||
(fn [{:keys [db]} [{:keys [amount-in amount-out]}]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
{:keys [asset-to-pay asset-to-receive
|
||||
network]} (get-in db [:wallet :ui :swap])
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks ((if test-networks-enabled? :test :prod)
|
||||
(get-in db [:wallet :networks]))
|
||||
network-chain-ids (map :chain-id networks)
|
||||
pay-token-decimal (:decimals asset-to-pay)
|
||||
pay-token-id (:symbol asset-to-pay)
|
||||
receive-token-id (:symbol asset-to-receive)
|
||||
receive-token-decimals (:decimals asset-to-receive)
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in-hex (if amount-in
|
||||
(send-utils/amount-in-hex amount-in pay-token-decimal)
|
||||
0)
|
||||
amount-out-hex (when amount-out
|
||||
(send-utils/amount-in-hex amount-out receive-token-decimals))
|
||||
to-address wallet-address
|
||||
from-address wallet-address
|
||||
swap-chain-id (:chain-id network)
|
||||
disabled-to-chain-ids (filter #(not= % swap-chain-id) network-chain-ids)
|
||||
disabled-from-chain-ids (filter #(not= % swap-chain-id) network-chain-ids)
|
||||
from-locked-amount {}
|
||||
send-type constants/send-type-swap
|
||||
request-uuid (str (random-uuid))
|
||||
params [(cond->
|
||||
{:uuid request-uuid
|
||||
:sendType send-type
|
||||
:addrFrom from-address
|
||||
:addrTo to-address
|
||||
:tokenID pay-token-id
|
||||
:toTokenID receive-token-id
|
||||
:disabledFromChainIDs disabled-from-chain-ids
|
||||
:disabledToChainIDs disabled-to-chain-ids
|
||||
:gasFeeMode gas-rates
|
||||
:fromLockedAmount from-locked-amount}
|
||||
amount-in (assoc :amountIn amount-in-hex)
|
||||
amount-out (assoc :amountOut amount-out-hex))]]
|
||||
|
||||
(when-let [amount (or amount-in amount-out)]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
#(-> %
|
||||
(assoc
|
||||
:last-request-uuid request-uuid
|
||||
:amount amount
|
||||
:loading-swap-proposal? true)
|
||||
(dissoc :error-response)))
|
||||
:json-rpc/call [{:method "wallet_getSuggestedRoutesV2Async"
|
||||
:params params
|
||||
:on-error (fn [error]
|
||||
(rf/dispatch [:wallet/swap-proposal-error error])
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/start-get-swap-proposal
|
||||
:error (:message error)
|
||||
:params params}))}]}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-proposal-success
|
||||
(fn [{:keys [db]} [swap-proposal]]
|
||||
(let [last-request-uuid (get-in db [:wallet :ui :swap :last-request-uuid])
|
||||
request-uuid (:uuid swap-proposal)
|
||||
best-routes (:best swap-proposal)
|
||||
error-response (:error-response swap-proposal)]
|
||||
(when (= request-uuid last-request-uuid)
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
assoc
|
||||
:swap-proposal (first best-routes)
|
||||
:error-response (when (empty? best-routes) error-response)
|
||||
:loading-swap-proposal? false)}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-proposal-error
|
||||
(fn [{:keys [db]} [error-message]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :swap] dissoc :route :swap-proposal)
|
||||
(assoc-in [:wallet :ui :swap :loading-swap-proposal?] false)
|
||||
(assoc-in [:wallet :ui :swap :error-response] error-message))
|
||||
:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-proposal-error
|
||||
:type :negative
|
||||
:text error-message}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/stop-get-swap-proposal
|
||||
(fn []
|
||||
{:json-rpc/call [{:method "wallet_stopSuggestedRoutesV2AsyncCalcualtion"
|
||||
:params []
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to stop fetching swap proposals"
|
||||
{:event :wallet/stop-get-swap-proposal
|
||||
:error error}))}]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-swap-proposal
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
dissoc
|
||||
:last-request-uuid
|
||||
:swap-proposal
|
||||
:error-response
|
||||
:loading-swap-proposal?
|
||||
:approval-transaction-id)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-swap
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui] dissoc :swap)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [wallet-address (get-in db
|
||||
[:wallet
|
||||
:current-viewing-account-address])
|
||||
{:keys [asset-to-pay asset-to-receive
|
||||
swap-proposal network amount
|
||||
approval-transaction-id
|
||||
max-slippage]} (get-in db [:wallet :ui :swap])
|
||||
transactions (get-in db [:wallet :transactions])
|
||||
approval-transaction (when approval-transaction-id
|
||||
(get transactions approval-transaction-id))
|
||||
already-approved? (and approval-transaction
|
||||
(= (:status approval-transaction)
|
||||
:confirmed))
|
||||
approval-required? (and (:approval-required swap-proposal)
|
||||
(not already-approved?))
|
||||
multi-transaction-type constants/multi-transaction-type-swap
|
||||
swap-chain-id (:chain-id network)
|
||||
token-id-from (:symbol asset-to-pay)
|
||||
token-id-to (:symbol asset-to-receive)
|
||||
erc20-transfer? (and asset-to-pay (not= token-id-from "ETH"))
|
||||
eth-transfer? (and asset-to-pay (not erc20-transfer?))
|
||||
token-address (when erc20-transfer?
|
||||
(get-in asset-to-pay
|
||||
[:balances-per-chain swap-chain-id
|
||||
:address]))
|
||||
data (when erc20-transfer?
|
||||
(native-module/encode-transfer
|
||||
(address/normalized-hex wallet-address)
|
||||
(:amount-in swap-proposal)))
|
||||
transaction-paths (if approval-required?
|
||||
[(utils/approval-path
|
||||
{:route swap-proposal
|
||||
:token-address token-address
|
||||
:from-address wallet-address
|
||||
:to-address wallet-address})]
|
||||
[(utils/transaction-path
|
||||
{:to-address wallet-address
|
||||
:from-address wallet-address
|
||||
:route swap-proposal
|
||||
:token-address token-address
|
||||
:token-id-from token-id-from
|
||||
:token-id-to token-id-to
|
||||
:data data
|
||||
:slippage-percentage max-slippage
|
||||
:eth-transfer? eth-transfer?})])
|
||||
request-params [(utils/multi-transaction-command
|
||||
{:from-address wallet-address
|
||||
:to-address wallet-address
|
||||
:from-asset token-id-from
|
||||
:to-asset (if approval-required?
|
||||
token-id-from
|
||||
token-id-to)
|
||||
:amount-out (if eth-transfer?
|
||||
(:amount-out swap-proposal)
|
||||
"0x0")
|
||||
:multi-transaction-type
|
||||
multi-transaction-type})
|
||||
transaction-paths
|
||||
sha3-pwd]]
|
||||
(log/info "multi transaction called")
|
||||
{:json-rpc/call [{:method "wallet_createMultiTransaction"
|
||||
:params request-params
|
||||
:on-success (fn [result]
|
||||
(when result
|
||||
(let [receive-token-decimals (:decimals asset-to-receive)
|
||||
amount-out (:amount-out swap-proposal)
|
||||
decimals-to-display
|
||||
(min
|
||||
receive-token-decimals
|
||||
constants/min-token-decimals-to-display)
|
||||
receive-amount (when amount-out
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed (number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(hex/normalize-hex
|
||||
amount-out))
|
||||
receive-token-decimals)
|
||||
decimals-to-display)))]
|
||||
(rf/dispatch [:wallet.swap/add-authorized-transaction
|
||||
(cond-> {:transaction result
|
||||
:approval-transaction?
|
||||
approval-required?}
|
||||
(not approval-required?)
|
||||
(assoc :swap-data
|
||||
{:pay-token-symbol token-id-from
|
||||
:pay-amount amount
|
||||
:receive-token-symbol token-id-to
|
||||
:receive-amount receive-amount}))])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:dismiss-modal
|
||||
(if approval-required?
|
||||
:screen/wallet.swap-set-spending-cap
|
||||
:screen/wallet.swap-confirmation)])
|
||||
(when-not approval-required?
|
||||
(rf/dispatch [:wallet/select-account-tab :activity])
|
||||
(debounce/debounce-and-dispatch [:wallet/clean-swap] 1000)
|
||||
(debounce/debounce-and-dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-transaction-pending
|
||||
:icon :i/info
|
||||
:type :neutral
|
||||
:text (i18n/label :t/swapping-to
|
||||
{:pay-amount amount
|
||||
:pay-token-symbol token-id-from
|
||||
:receive-token-symbol token-id-to
|
||||
:receive-amount receive-amount})}]
|
||||
500)))))
|
||||
:on-error (fn [error]
|
||||
(log/error "failed swap transaction"
|
||||
{:event :wallet/swap-transaction
|
||||
:error error
|
||||
:params request-params})
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :swap-transaction-error
|
||||
:type :negative
|
||||
:text (:message error)}]))}]})))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/add-authorized-transaction
|
||||
(fn [{:keys [db]} [{:keys [transaction swap-data approval-transaction?]}]]
|
||||
(let [transactions (get-in db [:wallet :transactions] {})
|
||||
transaction-batch-id (:id transaction)
|
||||
transaction-hashes (:hashes transaction)
|
||||
transaction-ids (flatten (vals transaction-hashes))
|
||||
transaction-id (first transaction-ids)
|
||||
transaction-details (cond-> (send-utils/map-multitransaction-by-ids transaction-batch-id
|
||||
transaction-hashes)
|
||||
:always (assoc-in [transaction-id :tx-type] :swap)
|
||||
swap-data (assoc-in [transaction-id :swap-data] swap-data))
|
||||
swap-transaction-ids (get-in db [:wallet :swap-transaction-ids])]
|
||||
{:db (cond-> db
|
||||
:always (assoc-in [:wallet :transactions]
|
||||
(merge transactions transaction-details))
|
||||
:always (assoc-in [:wallet :ui :swap :transaction-ids] transaction-ids)
|
||||
approval-transaction? (assoc-in [:wallet :ui :swap :approval-transaction-id]
|
||||
transaction-id)
|
||||
(not approval-transaction?) (assoc-in [:wallet :swap-transaction-ids]
|
||||
(if swap-transaction-ids
|
||||
(conj swap-transaction-ids transaction-id)
|
||||
(hash-set transaction-id))))})))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/approve-transaction-update
|
||||
(fn [{:keys [db]} [{:keys [status]}]]
|
||||
(let [{:keys [amount asset-to-pay swap-proposal]} (get-in db [:wallet :ui :swap])
|
||||
provider-name (:bridge-name swap-proposal)
|
||||
token-symbol (:symbol asset-to-pay)
|
||||
current-viewing-account-address (get-in db
|
||||
[:wallet :current-viewing-account-address])
|
||||
account-name (get-in db
|
||||
[:wallet :accounts
|
||||
current-viewing-account-address :name])
|
||||
transaction-confirmed-or-failed? (#{:confirmed :failed} status)
|
||||
transaction-confirmed? (= status :confirmed)]
|
||||
(when transaction-confirmed-or-failed?
|
||||
(cond-> {:fx
|
||||
[[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :approve-transaction-update
|
||||
:type (if transaction-confirmed? :positive :negative)
|
||||
:text (if transaction-confirmed?
|
||||
(i18n/label :t/spending-cap-set
|
||||
{:amount amount
|
||||
:token-symbol token-symbol
|
||||
:provider-name provider-name
|
||||
:account-name account-name})
|
||||
(i18n/label :t/spending-cap-failed
|
||||
{:amount amount
|
||||
:token-symbol token-symbol
|
||||
:provider-name provider-name
|
||||
:account-name account-name}))}]]]}
|
||||
(not transaction-confirmed?)
|
||||
(assoc :db (update-in db [:wallet :ui :swap] dissoc :approval-transaction-id)))))))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/swap-transaction-update
|
||||
(fn [{:keys [db]} [{:keys [tx-hash status]}]]
|
||||
(let [{:keys [pay-amount pay-token-symbol
|
||||
receive-amount receive-token-symbol]} (get-in db
|
||||
[:wallet :transactions tx-hash
|
||||
:swap-data])
|
||||
transaction-confirmed-or-failed? (#{:confirmed :failed} status)
|
||||
transaction-confirmed? (= status :confirmed)]
|
||||
(when transaction-confirmed-or-failed?
|
||||
{:db (-> db
|
||||
(update-in [:wallet :swap-transaction-ids] disj tx-hash)
|
||||
(update-in [:wallet :transactions] dissoc tx-hash))
|
||||
:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-transaction-update
|
||||
:type (if transaction-confirmed? :positive :negative)
|
||||
:text (if transaction-confirmed?
|
||||
(i18n/label :t/swapped-to
|
||||
{:pay-amount pay-amount
|
||||
:pay-token-symbol pay-token-symbol
|
||||
:receive-token-symbol receive-token-symbol
|
||||
:receive-amount receive-amount})
|
||||
(i18n/label :t/swap-failed))}]]]}))))
|
||||
|
||||
@@ -18,18 +18,36 @@
|
||||
: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"
|
||||
:pay-token {:symbol "SNT"
|
||||
:address "0x432492384728934239789"}
|
||||
:receive-token {:symbol "USDT"
|
||||
:address "0x432492384728934239789"}})
|
||||
|
||||
(defn- assets-view
|
||||
[search-text on-change-text]
|
||||
(let [on-token-press (fn [token]
|
||||
(let [token-networks (:networks token)
|
||||
asset-to-receive (rf/sub [:wallet/token-by-symbol "DAI"])]
|
||||
asset-to-receive (rf/sub [:wallet/token-by-symbol "SNT"])]
|
||||
(rf/dispatch [:wallet.swap/select-asset-to-pay
|
||||
{:token token
|
||||
:network (when (= (count token-networks) 1)
|
||||
(first token-networks))
|
||||
:stack-id :screen/wallet.swap-select-asset-to-pay}])
|
||||
(rf/dispatch [:wallet.swap/select-asset-to-receive
|
||||
{:token asset-to-receive}])))]
|
||||
(rf/dispatch [:wallet.swap/select-asset-to-receive {:token asset-to-receive}])
|
||||
(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,7 +59,7 @@
|
||||
(let [[search-text set-search-text] (rn/use-state "")
|
||||
on-change-text #(set-search-text %)
|
||||
on-close (fn []
|
||||
(rf/dispatch [:wallet/clean-swap])
|
||||
(rf/dispatch [:wallet.swap/clean-asset-to-pay])
|
||||
(rf/dispatch [:navigate-back]))]
|
||||
[rn/safe-area-view {:style style/container}
|
||||
[account-switcher/view
|
||||
|
||||
@@ -7,100 +7,84 @@
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils.external-links :as external-links]
|
||||
[status-im.contexts.wallet.swap.set-spending-cap.style :as style]
|
||||
[utils.address :as address-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- swap-title
|
||||
[]
|
||||
(let [asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
pay-amount (rf/sub [:wallet/swap-pay-amount])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
provider (rf/sub [:wallet/swap-proposal-provider])
|
||||
pay-token-symbol (:symbol asset-to-pay)]
|
||||
[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 :set-spending-cap-of}
|
||||
(i18n/label :t/set-spending-cap-of)]]
|
||||
[rn/view {:style style/title-line-with-margin-top}
|
||||
[quo/summary-tag
|
||||
{:token pay-token-symbol
|
||||
:label (str pay-amount " " pay-token-symbol)
|
||||
:type :token}]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/title-container
|
||||
:accessibility-label :for}
|
||||
(i18n/label :t/for)]]
|
||||
[rn/view {:style style/title-line-with-margin-top}
|
||||
[quo/summary-tag
|
||||
{:label (:full-name provider)
|
||||
:type :network
|
||||
:image-source (resources/get-network (:name provider))
|
||||
:customization-color (:color provider)}]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/title-container
|
||||
:accessibility-label :on}
|
||||
(i18n/label :t/on)]]
|
||||
[rn/view {:style style/title-line-with-margin-top}
|
||||
[quo/summary-tag
|
||||
{:label (:name account)
|
||||
:type :account
|
||||
:emoji (:emoji account)
|
||||
:customization-color (:color account)}]]]))
|
||||
[{:keys [pay-token-symbol pay-amount account provider]}]
|
||||
[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 :set-spending-cap-of}
|
||||
(i18n/label :t/set-spending-cap-of)]]
|
||||
[rn/view {:style style/title-line-with-margin-top}
|
||||
[quo/summary-tag
|
||||
{:token pay-token-symbol
|
||||
:label (str pay-amount " " pay-token-symbol)
|
||||
:type :token}]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/title-container
|
||||
:accessibility-label :for}
|
||||
(i18n/label :t/for)]]
|
||||
[rn/view {:style style/title-line-with-margin-top}
|
||||
[quo/summary-tag
|
||||
{:label (:full-name provider)
|
||||
:type :network
|
||||
:image-source (resources/get-network (:name provider))
|
||||
:customization-color (:color provider)}]
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/title-container
|
||||
:accessibility-label :on}
|
||||
(i18n/label :t/on)]]
|
||||
[rn/view {:style style/title-line-with-margin-top}
|
||||
[quo/summary-tag
|
||||
{:label (:name account)
|
||||
:type :account
|
||||
:emoji (:emoji account)
|
||||
:customization-color (:color account)}]]])
|
||||
|
||||
(defn- spending-cap-section
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
pay-amount (rf/sub [:wallet/swap-pay-amount])
|
||||
pay-token-symbol (:symbol asset-to-pay)]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :spending-cap-label}
|
||||
(i18n/label :t/spending-cap)]
|
||||
[quo/approval-info
|
||||
{:type :spending-cap
|
||||
:unlimited-icon? false
|
||||
:label (str pay-amount " " pay-token-symbol)
|
||||
:avatar-props {:token pay-token-symbol}}]]))
|
||||
[{:keys [theme amount token-symbol]}]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :spending-cap-label}
|
||||
(i18n/label :t/spending-cap)]
|
||||
[quo/approval-info
|
||||
{:type :spending-cap
|
||||
:unlimited-icon? false
|
||||
:label (str amount " " token-symbol)
|
||||
:avatar-props {:token token-symbol}}]])
|
||||
|
||||
(defn- account-section
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
pay-amount (rf/sub [:wallet/swap-pay-amount])
|
||||
pay-token-symbol (:symbol asset-to-pay)]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :account-label}
|
||||
(i18n/label :t/account)]
|
||||
[quo/approval-info
|
||||
{:type :account
|
||||
:unlimited-icon? false
|
||||
:label (:name account)
|
||||
:description (address-utils/get-short-wallet-address (:address account))
|
||||
:tag-label (str pay-amount " " pay-token-symbol)
|
||||
:avatar-props {:emoji (:emoji account)
|
||||
:customization-color (:color account)}}]]))
|
||||
[{:keys [theme account pay-token-symbol pay-token-amount]}]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :account-label}
|
||||
(i18n/label :t/account)]
|
||||
[quo/approval-info
|
||||
{:type :account
|
||||
:unlimited-icon? false
|
||||
:label (:name account)
|
||||
:description (address-utils/get-short-wallet-address (:address account))
|
||||
:tag-label (str pay-token-amount " " pay-token-symbol)
|
||||
:avatar-props {:emoji (:emoji account)
|
||||
:customization-color (:color account)}}]])
|
||||
|
||||
(defn- on-option-press
|
||||
[{:keys [chain-id contract-address]}]
|
||||
@@ -119,52 +103,42 @@
|
||||
:right-icon :i/external}]]])}]))
|
||||
|
||||
(defn- token-section
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
network-chain-id (:chain-id network)
|
||||
pay-token-address (get-in asset-to-pay [:balances-per-chain network-chain-id :address])]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :token-label}
|
||||
(i18n/label :t/token)]
|
||||
[quo/approval-info
|
||||
{:type :token-contract
|
||||
:option-icon :i/options
|
||||
:on-option-press #(on-option-press {:chain-id network-chain-id
|
||||
:contract-address pay-token-address})
|
||||
:unlimited-icon? false
|
||||
:label pay-token-symbol
|
||||
:description (address-utils/get-short-wallet-address pay-token-address)
|
||||
:avatar-props {:token pay-token-symbol}}]]))
|
||||
[{:keys [theme token-address token-symbol network-chain-id]}]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :token-label}
|
||||
(i18n/label :t/token)]
|
||||
[quo/approval-info
|
||||
{:type :token-contract
|
||||
:option-icon :i/options
|
||||
:on-option-press #(on-option-press {:chain-id network-chain-id
|
||||
:contract-address token-address})
|
||||
:unlimited-icon? false
|
||||
:label token-symbol
|
||||
:description (address-utils/get-short-wallet-address token-address)
|
||||
:avatar-props {:token token-symbol}}]])
|
||||
|
||||
(defn- spender-contract-section
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
provider (rf/sub [:wallet/swap-proposal-provider])
|
||||
network-chain-id (:chain-id network)]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :spender-contract-label}
|
||||
(i18n/label :t/spender-contract)]
|
||||
[quo/approval-info
|
||||
{:type :token-contract
|
||||
:option-icon :i/options
|
||||
:on-option-press #(on-option-press {:chain-id network-chain-id
|
||||
:contract-address (:contract-address provider)})
|
||||
:unlimited-icon? false
|
||||
:label (:full-name provider)
|
||||
:description (address-utils/get-short-wallet-address (:contract-address provider))
|
||||
:avatar-props {:image (resources/get-network (:name provider))}}]]))
|
||||
[{:keys [theme provider network-chain-id]}]
|
||||
[rn/view {:style style/summary-section-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label :spender-contract-label}
|
||||
(i18n/label :t/spender-contract)]
|
||||
[quo/approval-info
|
||||
{:type :token-contract
|
||||
:option-icon :i/options
|
||||
:on-option-press #(on-option-press {:chain-id network-chain-id
|
||||
:contract-address (:contract-address provider)})
|
||||
:unlimited-icon? false
|
||||
:label (:full-name provider)
|
||||
:description (address-utils/get-short-wallet-address (:contract-address provider))
|
||||
:avatar-props {:image (resources/get-network (:name provider))}}]])
|
||||
|
||||
(defn- data-item
|
||||
[{:keys [network-image title subtitle size loading?]}]
|
||||
@@ -180,52 +154,56 @@
|
||||
:size size}])
|
||||
|
||||
(defn- transaction-details
|
||||
[]
|
||||
(let [network (rf/sub [:wallet/swap-network])
|
||||
max-fees (rf/sub [:wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
constants/token-for-fees-symbol])
|
||||
loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
estimated-time (rf/sub [:wallet/swap-proposal-estimated-time])]
|
||||
[rn/view {:style style/details-container}
|
||||
[:<>
|
||||
[data-item
|
||||
{:title (i18n/label :t/network)
|
||||
:subtitle (:full-name network)
|
||||
:network-image (:source network)}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-fees)
|
||||
:subtitle max-fees
|
||||
:loading? loading-fees?
|
||||
:size :small}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
:subtitle (i18n/label :t/time-in-mins {:minutes (str estimated-time)})}]]]))
|
||||
[{:keys [estimated-time-min max-fees network loading-fees?]}]
|
||||
[rn/view {:style style/details-container}
|
||||
[:<>
|
||||
[data-item
|
||||
{:title (i18n/label :t/network)
|
||||
:subtitle (:full-name network)
|
||||
:network-image (:source network)}]
|
||||
[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?
|
||||
:size :small}]]])
|
||||
|
||||
(defn- slide-button
|
||||
[]
|
||||
(let [loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
on-auth-success (rn/use-callback #(rf/dispatch
|
||||
[:wallet/swap-transaction
|
||||
(security/safe-unmask-data %)]))]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-sign)
|
||||
:container-style {:z-index 2}
|
||||
:customization-color (:color account)
|
||||
:disabled? loading-fees?
|
||||
:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/confirm)}]))
|
||||
|
||||
(defn- footer
|
||||
[]
|
||||
[rn/view {:style {:margin-bottom -10}}
|
||||
[transaction-details]
|
||||
[slide-button]])
|
||||
(defn footer
|
||||
[{:keys [estimated-time-min native-currency-symbol network theme account-color loading-fees?]}]
|
||||
(let [fee-formatted (rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])
|
||||
on-auth-success (rn/use-callback #(js/alert "Not implemented yet"))]
|
||||
[rn/view {:style {:margin-bottom -10}}
|
||||
[transaction-details
|
||||
{:estimated-time-min estimated-time-min
|
||||
:max-fees fee-formatted
|
||||
:network network
|
||||
: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?
|
||||
:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/confirm)}]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [account (rf/sub [:wallet/current-viewing-account])]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
swap-transaction-data (rf/sub [:wallet/swap])
|
||||
{:keys [asset-to-pay network pay-amount
|
||||
providers swap-proposal
|
||||
loading-fees?]} swap-transaction-data
|
||||
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 style/container}
|
||||
[floating-button-page/view
|
||||
{:footer-container-padding 0
|
||||
@@ -235,12 +213,37 @@
|
||||
:margin-top 8
|
||||
:background :blur
|
||||
:accessibility-label :top-bar}]
|
||||
:footer [footer]
|
||||
:footer [footer
|
||||
{:estimated-time-min estimated-time-min
|
||||
:native-currency-symbol native-currency-symbol
|
||||
:network network
|
||||
:account-color account-color
|
||||
:provider provider
|
||||
:loading-fees? loading-fees?
|
||||
:theme theme}]
|
||||
:gradient-cover? true
|
||||
:customization-color (:color account)}
|
||||
:customization-color account-color}
|
||||
[:<>
|
||||
[swap-title]
|
||||
[spending-cap-section]
|
||||
[account-section]
|
||||
[token-section]
|
||||
[spender-contract-section]]]]))
|
||||
[swap-title
|
||||
{:pay-token-symbol pay-token-symbol
|
||||
:pay-amount pay-amount
|
||||
:account account
|
||||
:provider provider}]
|
||||
[spending-cap-section
|
||||
{:token-symbol pay-token-symbol
|
||||
:amount pay-amount
|
||||
:theme theme}]
|
||||
[account-section
|
||||
{:account account
|
||||
:pay-token-symbol pay-token-symbol
|
||||
:pay-token-amount pay-amount
|
||||
:theme theme}]
|
||||
[token-section
|
||||
{:token-symbol pay-token-symbol
|
||||
:token-address pay-token-address
|
||||
:network-chain-id (:chain-id network)
|
||||
:theme theme}]
|
||||
[spender-contract-section
|
||||
{:provider provider
|
||||
:network-chain-id (:chain-id network)
|
||||
:theme theme}]]]]))
|
||||
|
||||
@@ -22,19 +22,14 @@
|
||||
:height 36
|
||||
:background-color :transparent})
|
||||
|
||||
(defn swap-order-button
|
||||
[approval-required?]
|
||||
{:margin-top (if approval-required? 3 -9)
|
||||
(def swap-order-button
|
||||
{:margin-top -9
|
||||
:z-index 2
|
||||
:align-self :center})
|
||||
|
||||
(defn receive-token-swap-input-container
|
||||
[approval-required?]
|
||||
{:margin-top (if approval-required? 3 -9)})
|
||||
(def receive-token-swap-input-container
|
||||
{:margin-top -9})
|
||||
|
||||
(def footer-container
|
||||
{:flex 1
|
||||
:justify-content :flex-end})
|
||||
|
||||
(def alert-banner
|
||||
{:height 40})
|
||||
|
||||
@@ -1,35 +1,13 @@
|
||||
(ns status-im.contexts.wallet.swap.setup-swap.view
|
||||
(:require [clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.core :as quo]
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.controlled-input.utils :as controlled-input]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.swap.setup-swap.style :as style]
|
||||
[utils.hex :as hex]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string :as utils.string]))
|
||||
|
||||
(def ^:private default-text-for-unfocused-input "0.00")
|
||||
|
||||
(defn- on-close
|
||||
[]
|
||||
(rf/dispatch [:wallet/clean-swap-proposal])
|
||||
(events-helper/navigate-back))
|
||||
|
||||
(defn- fetch-swap-proposal
|
||||
[{:keys [amount valid-input?]}]
|
||||
(if valid-input?
|
||||
(rf/dispatch [:wallet/start-get-swap-proposal {:amount-in amount}])
|
||||
(rf/dispatch [:wallet/clean-swap-proposal])))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- data-item
|
||||
[{:keys [title subtitle size subtitle-icon loading?]}]
|
||||
@@ -45,260 +23,110 @@
|
||||
:icon subtitle-icon}])
|
||||
|
||||
(defn- transaction-details
|
||||
[]
|
||||
(let [max-fees (rf/sub [:wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
constants/token-for-fees-symbol])
|
||||
max-slippage (rf/sub [:wallet/swap-max-slippage])
|
||||
loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
loading? (or loading-fees? loading-swap-proposal?)]
|
||||
[{:keys [max-slippage native-currency-symbol loading-fees?]}]
|
||||
(let [max-fees (rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])]
|
||||
[rn/view {:style style/details-container}
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-fees)
|
||||
:subtitle max-fees
|
||||
:loading? loading?
|
||||
:loading? loading-fees?
|
||||
:size :small}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-slippage)
|
||||
:subtitle max-slippage
|
||||
:subtitle-icon :i/edit
|
||||
:size :small
|
||||
:loading? loading?}]]))
|
||||
|
||||
(defn- pay-token-input
|
||||
[{:keys [input-state on-max-press on-input-focus on-token-press on-approve-press input-focused?]}]
|
||||
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
currency (rf/sub [:profile/currency])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal])
|
||||
approval-required (rf/sub [:wallet/swap-proposal-approval-required])
|
||||
approval-amount-required (rf/sub [:wallet/swap-proposal-approval-amount-required])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
approval-transaction-status (rf/sub [:wallet/swap-approval-transaction-status])
|
||||
pay-input-num-value (controlled-input/numeric-value input-state)
|
||||
pay-input-amount (controlled-input/input-value input-state)
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
pay-token-decimals (:decimals asset-to-pay)
|
||||
pay-token-balance-selected-chain (get-in asset-to-pay
|
||||
[:balances-per-chain
|
||||
(:chain-id network) :balance]
|
||||
0)
|
||||
pay-token-fiat-value (str
|
||||
(utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance pay-input-num-value
|
||||
:token asset-to-pay}))
|
||||
available-crypto-limit (number/remove-trailing-zeroes
|
||||
(.toFixed (money/bignumber
|
||||
pay-token-balance-selected-chain)
|
||||
(min pay-token-decimals
|
||||
constants/min-token-decimals-to-display)))
|
||||
approval-amount-required-num (when approval-amount-required
|
||||
(str (number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(hex/normalize-hex
|
||||
approval-amount-required))
|
||||
pay-token-decimals)))
|
||||
pay-input-error? (and (not (string/blank? pay-input-amount))
|
||||
(money/greater-than
|
||||
(money/bignumber pay-input-num-value)
|
||||
(money/bignumber
|
||||
pay-token-balance-selected-chain)))
|
||||
valid-pay-input? (and
|
||||
(not (string/blank?
|
||||
pay-input-amount))
|
||||
(> pay-input-amount 0)
|
||||
(not pay-input-error?))
|
||||
request-fetch-swap-proposal (rn/use-callback
|
||||
(fn []
|
||||
(fetch-swap-proposal
|
||||
{:amount pay-input-amount
|
||||
:valid-input? valid-pay-input?}))
|
||||
[pay-input-amount])]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(request-fetch-swap-proposal))
|
||||
[pay-input-amount])
|
||||
[quo/swap-input
|
||||
{:type :pay
|
||||
:error? pay-input-error?
|
||||
:token pay-token-symbol
|
||||
:customization-color :blue
|
||||
:show-approval-label? (and swap-proposal approval-required)
|
||||
:auto-focus? true
|
||||
:show-keyboard? false
|
||||
:status (cond
|
||||
(and loading-swap-proposal? (not input-focused?)) :loading
|
||||
input-focused? :typing
|
||||
:else :disabled)
|
||||
:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:on-max-press #(on-max-press available-crypto-limit)
|
||||
:on-input-focus on-input-focus
|
||||
:value pay-input-amount
|
||||
:fiat-value pay-token-fiat-value
|
||||
:network-tag-props {:title (i18n/label :t/max-token
|
||||
{:number available-crypto-limit
|
||||
:token-symbol pay-token-symbol})
|
||||
:networks [{:source (:source network)}]}
|
||||
:approval-label-props {:status (case approval-transaction-status
|
||||
:pending :approving
|
||||
:confirmed :approved
|
||||
:finalised :approved
|
||||
:approve)
|
||||
:token-value approval-amount-required-num
|
||||
:button-props {:on-press on-approve-press}
|
||||
:customization-color account-color
|
||||
:token-symbol pay-token-symbol}}]))
|
||||
|
||||
(defn- swap-order-button
|
||||
[{:keys [on-press]}]
|
||||
(let [approval-required? (rf/sub [:wallet/swap-proposal-approval-required])]
|
||||
[quo/swap-order-button
|
||||
{:container-style (style/swap-order-button approval-required?)
|
||||
:on-press on-press}]))
|
||||
|
||||
(defn- receive-token-input
|
||||
[{:keys [on-input-focus on-token-press input-focused?]}]
|
||||
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
amount-out (rf/sub [:wallet/swap-proposal-amount-out])
|
||||
approval-required? (rf/sub [:wallet/swap-proposal-approval-required])
|
||||
receive-token-symbol (:symbol asset-to-receive)
|
||||
receive-token-decimals (:decimals asset-to-receive)
|
||||
amount-out-whole-number (when amount-out
|
||||
(number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(utils.hex/normalize-hex
|
||||
amount-out))
|
||||
receive-token-decimals))
|
||||
amount-out-num (if amount-out-whole-number
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed amount-out-whole-number receive-token-decimals))
|
||||
default-text-for-unfocused-input)
|
||||
receive-token-fiat-value (str (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (or amount-out-whole-number 0)
|
||||
:token asset-to-receive}))]
|
||||
[quo/swap-input
|
||||
{:type :receive
|
||||
:error? false
|
||||
:token receive-token-symbol
|
||||
:customization-color account-color
|
||||
:show-approval-label? false
|
||||
:enable-swap? true
|
||||
:input-disabled? true
|
||||
:show-keyboard? false
|
||||
:status (cond
|
||||
(and loading-swap-proposal? (not input-focused?)) :loading
|
||||
input-focused? :typing
|
||||
:else :disabled)
|
||||
:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:on-input-focus on-input-focus
|
||||
:value amount-out-num
|
||||
:fiat-value receive-token-fiat-value
|
||||
:container-style (style/receive-token-swap-input-container approval-required?)}]))
|
||||
|
||||
(defn- action-button
|
||||
[{:keys [on-press]}]
|
||||
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal])
|
||||
loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
approval-required? (rf/sub [:wallet/swap-proposal-approval-required])
|
||||
approval-transaction-status (rf/sub [:wallet/swap-approval-transaction-status])]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/review-swap)
|
||||
:button-one-props {:disabled? (or (not swap-proposal)
|
||||
(and approval-required?
|
||||
(not= approval-transaction-status :confirmed))
|
||||
loading-swap-proposal?
|
||||
loading-fees?)
|
||||
:customization-color account-color
|
||||
:on-press on-press}}]))
|
||||
:loading? loading-fees?}]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [[pay-input-state set-pay-input-state] (rn/use-state controlled-input/init-state)
|
||||
[pay-input-focused? set-pay-input-focused?] (rn/use-state true)
|
||||
error-response (rf/sub [:wallet/swap-error-response])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal])
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
pay-input-amount (controlled-input/input-value pay-input-state)
|
||||
pay-token-decimals (:decimals asset-to-pay)
|
||||
on-review-swap-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.swap-confirmation
|
||||
:screen/wallet.setup-swap]])))
|
||||
on-press (rn/use-callback
|
||||
(fn [c]
|
||||
(let
|
||||
[new-text (str pay-input-amount c)
|
||||
valid-amount?
|
||||
(utils.string/valid-amount-for-token-decimals?
|
||||
pay-token-decimals
|
||||
new-text)]
|
||||
(when valid-amount?
|
||||
(set-pay-input-state
|
||||
#(controlled-input/add-character % c))))))
|
||||
on-long-press (rn/use-callback
|
||||
(fn []
|
||||
(set-pay-input-state controlled-input/delete-all)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))
|
||||
delete (rn/use-callback
|
||||
(fn []
|
||||
(set-pay-input-state
|
||||
controlled-input/delete-last)
|
||||
(rf/dispatch [:wallet/clean-swap-proposal])))
|
||||
on-max-press (rn/use-callback
|
||||
(fn [max-value]
|
||||
(set-pay-input-state
|
||||
(fn [input-state]
|
||||
(controlled-input/set-input-value
|
||||
input-state
|
||||
max-value)))))]
|
||||
(let [[pay-value set-pay-value] (rn/use-state "")
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
{:keys [max-slippage swap-proposal loading-fees?
|
||||
receive-amount network]} (rf/sub [:wallet/swap])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
|
||||
|
||||
pay-token-fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (or pay-value 0)
|
||||
:token asset-to-pay})
|
||||
receive-token-fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (or receive-amount 0)
|
||||
:token asset-to-receive})
|
||||
native-currency-symbol (get-in swap-proposal
|
||||
[:from :native-currency-symbol])
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
receive-token-symbol (:symbol asset-to-receive)
|
||||
on-press (fn [v] (set-pay-value (str pay-value v)))
|
||||
delete (fn []
|
||||
(set-pay-value #(subs % 0 (dec (count %)))))]
|
||||
[rn/view {:style style/container}
|
||||
[account-switcher/view
|
||||
{:on-press on-close
|
||||
{:on-press events-helper/navigate-back
|
||||
:icon-name :i/arrow-left
|
||||
:margin-top (safe-area/get-top)
|
||||
:switcher-type :select-account}]
|
||||
[rn/view {:style style/inputs-container}
|
||||
[pay-token-input
|
||||
{:input-state pay-input-state
|
||||
:on-max-press on-max-press
|
||||
:input-focused? pay-input-focused?
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-approve-press #(rf/dispatch [:open-modal :screen/wallet.swap-set-spending-cap])
|
||||
:on-input-focus (fn []
|
||||
(when platform/android? (rf/dispatch [:dismiss-keyboard]))
|
||||
(set-pay-input-focused? true))}]
|
||||
[swap-order-button {:on-press #(js/alert "Swap Order Pressed")}]
|
||||
[receive-token-input
|
||||
{:input-focused? (not pay-input-focused?)
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-input-focus #(set-pay-input-focused? false)}]]
|
||||
[quo/swap-input
|
||||
{:type :pay
|
||||
:error? false
|
||||
:token pay-token-symbol
|
||||
:customization-color :blue
|
||||
:show-approval-label? false
|
||||
:status :default
|
||||
:currency-symbol currency-symbol
|
||||
:on-swap-press #(js/alert "Swap Pressed")
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-max-press #(js/alert "Max Pressed")
|
||||
:value pay-value
|
||||
:fiat-value pay-token-fiat-value
|
||||
:network-tag-props {:title (i18n/label :t/max-token
|
||||
{:number 200
|
||||
:token-symbol pay-token-symbol})
|
||||
:networks [{:source (:source network)}]}
|
||||
:approval-label-props {:status :approve
|
||||
:token-value pay-value
|
||||
:button-props {:on-press
|
||||
#(js/alert "Approve Pressed")}
|
||||
:customization-color color
|
||||
:token-symbol pay-token-symbol}}]
|
||||
[quo/swap-order-button
|
||||
{:container-style style/swap-order-button
|
||||
:on-press #(js/alert "Pressed")}]
|
||||
[quo/swap-input
|
||||
{:type :receive
|
||||
:error? false
|
||||
:token receive-token-symbol
|
||||
:customization-color color
|
||||
:show-approval-label? false
|
||||
:enable-swap? true
|
||||
:status :default
|
||||
:currency-symbol currency-symbol
|
||||
:on-swap-press #(js/alert "Swap Pressed")
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-max-press #(js/alert "Max Pressed")
|
||||
:value receive-amount
|
||||
:fiat-value receive-token-fiat-value
|
||||
:container-style style/receive-token-swap-input-container}]]
|
||||
[rn/view {:style style/footer-container}
|
||||
(when error-response
|
||||
[quo/alert-banner
|
||||
{:container-style style/alert-banner
|
||||
:text (i18n/label :t/something-went-wrong-please-try-again-later)}])
|
||||
(when (or loading-swap-proposal? swap-proposal)
|
||||
[transaction-details])
|
||||
[action-button {:on-press on-review-swap-press}]]
|
||||
(when swap-proposal
|
||||
[transaction-details
|
||||
{:native-currency-symbol native-currency-symbol
|
||||
:max-slippage max-slippage
|
||||
:loading-fees? loading-fees?}])
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/review-swap)
|
||||
:button-one-props {:disabled? (or (not swap-proposal)
|
||||
loading-fees?)
|
||||
:customization-color color
|
||||
:on-press #(js/alert "Review swap pressed")}}]]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style style/keyboard-container
|
||||
:left-action :dot
|
||||
:delete-key? true
|
||||
:on-press on-press
|
||||
:on-delete delete
|
||||
:on-long-press on-long-press}]]))
|
||||
:on-delete delete}]]))
|
||||
|
||||
@@ -37,7 +37,3 @@
|
||||
(def providers-container
|
||||
{:align-items :center
|
||||
:margin-top 12})
|
||||
|
||||
(defn swaps-powered-by
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-70 theme)})
|
||||
|
||||
@@ -1,66 +1,58 @@
|
||||
(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.constants :as constants]
|
||||
[status-im.contexts.wallet.swap.swap-confirmation.style :as style]
|
||||
[utils.address :as address-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- on-close-action
|
||||
[]
|
||||
(rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn- swap-title
|
||||
[]
|
||||
(let [asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
receive-amount (rf/sub [:wallet/swap-receive-amount])
|
||||
pay-amount (rf/sub [:wallet/swap-pay-amount])
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
receive-token-symbol (:symbol asset-to-receive)]
|
||||
[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)}]]]))
|
||||
[{: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]}]
|
||||
@@ -82,44 +74,6 @@
|
||||
:address (address-utils/get-shortened-compressed-key token-address)
|
||||
:size 32}}]]))
|
||||
|
||||
(defn- pay-section
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
pay-amount (rf/sub [:wallet/swap-pay-amount])
|
||||
network-chain-id (:chain-id network)
|
||||
network-name (:network-name network)
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
pay-token-address (get-in asset-to-pay [:balances-per-chain network-chain-id :address])]
|
||||
[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
|
||||
:theme theme}]))
|
||||
|
||||
(defn- receive-section
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
receive-amount (rf/sub [:wallet/swap-receive-amount])
|
||||
network-chain-id (:chain-id network)
|
||||
network-name (:network-name network)
|
||||
receive-token-symbol (:symbol asset-to-receive)
|
||||
receive-token-address (get-in asset-to-receive [:balances-per-chain network-chain-id :address])]
|
||||
[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
|
||||
:theme theme}]))
|
||||
|
||||
(defn- data-item
|
||||
[{:keys [title subtitle loading?]}]
|
||||
[quo/data-item
|
||||
@@ -132,59 +86,64 @@
|
||||
:subtitle subtitle}])
|
||||
|
||||
(defn- transaction-details
|
||||
[]
|
||||
(let [max-fees (rf/sub [:wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
constants/token-for-fees-symbol])
|
||||
estimated-time (rf/sub [:wallet/swap-proposal-estimated-time])
|
||||
loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
max-slippage (rf/sub [:wallet/swap-max-slippage])]
|
||||
[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)})}]
|
||||
[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- slide-button
|
||||
[]
|
||||
(let [loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)
|
||||
on-auth-success (rn/use-callback #(rf/dispatch
|
||||
[:wallet/swap-transaction
|
||||
(security/safe-unmask-data %)]))]
|
||||
[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)
|
||||
:on-auth-success on-auth-success}]))
|
||||
[{: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
|
||||
[]
|
||||
(let [provider (rf/sub [:wallet/swap-proposal-provider])
|
||||
theme (quo.theme/use-theme)]
|
||||
[{:keys [estimated-time-min native-currency-symbol max-slippage theme account-color provider
|
||||
loading-fees?]}]
|
||||
(let [fee-formatted (rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])]
|
||||
[:<>
|
||||
[transaction-details]
|
||||
[slide-button]
|
||||
[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 (style/swaps-powered-by theme)}
|
||||
(i18n/label :t/swaps-powered-by {:provider (:full-name provider)})]]]))
|
||||
: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 [account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)]
|
||||
(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
|
||||
@@ -194,10 +153,36 @@
|
||||
:margin-top (safe-area/get-top)
|
||||
:background :blur
|
||||
:accessibility-label :top-bar}]
|
||||
:footer [footer]
|
||||
: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-section]
|
||||
[receive-section]]]]))
|
||||
[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}]]]]))
|
||||
|
||||
@@ -50,9 +50,7 @@
|
||||
|
||||
(defn get-session-dapp-metadata
|
||||
[proposal]
|
||||
(let [metadata (get-in proposal [:params :proposer :metadata])
|
||||
origin (get-in proposal [:verifyContext :verified :origin])]
|
||||
(or metadata {:url origin})))
|
||||
(get-in proposal [:params :proposer :metadata]))
|
||||
|
||||
(defn get-current-request-dapp
|
||||
[request sessions]
|
||||
|
||||
@@ -109,12 +109,9 @@
|
||||
(if (wallet-connect-core/event-should-be-handled? db event)
|
||||
{:fx [[:dispatch [:wallet-connect/process-session-request event]]]}
|
||||
{:fx [[:dispatch
|
||||
[:wallet-connect/show-session-networks-unsupported-toast event]]
|
||||
[:dispatch
|
||||
[:wallet-connect/send-response
|
||||
{:request event
|
||||
:error (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-rejected-chains-error-key)}]]]})))
|
||||
{:error (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-rejected-chains-error-key)}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-delete
|
||||
|
||||
@@ -115,9 +115,8 @@
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/send-response
|
||||
(fn [{:keys [db]} [{:keys [request result error]}]]
|
||||
(when-let [{:keys [id topic] :as event} (or request
|
||||
(get-in db [:wallet-connect/current-request :event]))]
|
||||
(fn [{:keys [db]} [{:keys [result error]}]]
|
||||
(when-let [{:keys [id topic] :as event} (get-in db [:wallet-connect/current-request :event])]
|
||||
(let [method (wallet-connect-core/get-request-method event)
|
||||
web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:db (assoc-in db [:wallet-connect/current-request :response-sent?] true)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.subs.wallet.activities
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.foundations.resources :as quo.resources]
|
||||
[quo.foundations.resources]
|
||||
@@ -32,6 +33,12 @@
|
||||
(native-module/hex-to-number)
|
||||
(str)))
|
||||
|
||||
(defn- normalize-nft-name
|
||||
[token-id nft-name]
|
||||
(if (and (some? token-id) (string/blank? nft-name))
|
||||
"Unknown"
|
||||
nft-name))
|
||||
|
||||
(defn- get-token-amount
|
||||
[token amount]
|
||||
(let [token-type (:token-type token)]
|
||||
@@ -70,7 +77,7 @@
|
||||
(defn- process-activity-by-type
|
||||
[chain-id->network-name
|
||||
{:keys [activity-type activity-status timestamp sender recipient token-in token-out
|
||||
chain-id-in chain-id-out]
|
||||
chain-id-in chain-id-out nft-name]
|
||||
:as data}]
|
||||
(let [network-name (chain-id->network-name (or chain-id-in chain-id-out))
|
||||
token-id (some-> (or token-in token-out)
|
||||
@@ -84,7 +91,8 @@
|
||||
:network-name network-name
|
||||
:token-id token-id
|
||||
:status (constants/wallet-activity-status->name activity-status)
|
||||
:network-logo (quo.resources/get-network network-name))]
|
||||
:network-logo (quo.resources/get-network network-name)
|
||||
:nft-name (normalize-nft-name token-id nft-name))]
|
||||
(condp = activity-type
|
||||
constants/wallet-activity-type-send
|
||||
(process-send-activity activity)
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
(ns status-im.subs.wallet.swap
|
||||
(:require [clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as rf]
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[utils.hex :as hex]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]))
|
||||
[utils.money :as money]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap
|
||||
@@ -24,16 +19,6 @@
|
||||
:<- [:wallet/swap]
|
||||
:-> :asset-to-receive)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-network
|
||||
:<- [:wallet/swap]
|
||||
:-> :network)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-error-response
|
||||
:<- [:wallet/swap]
|
||||
:-> :error-response)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-asset-to-pay-token-symbol
|
||||
:<- [:wallet/swap-asset-to-pay]
|
||||
@@ -77,127 +62,3 @@
|
||||
:wallet/swap-max-slippage
|
||||
:<- [:wallet/swap]
|
||||
:-> :max-slippage)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-loading-fees?
|
||||
:<- [:wallet/swap]
|
||||
:-> :loading-fees?)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-approval-transaction-id
|
||||
:<- [:wallet/swap]
|
||||
:-> :approval-transaction-id)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-approval-transaction-status
|
||||
:<- [:wallet/transactions]
|
||||
:<- [:wallet/swap-approval-transaction-id]
|
||||
(fn [[transactions approval-transaction-id]]
|
||||
(get-in transactions [approval-transaction-id :status])))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal
|
||||
:<- [:wallet/swap]
|
||||
:-> :swap-proposal)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-loading-swap-proposal?
|
||||
:<- [:wallet/swap]
|
||||
:-> :loading-swap-proposal?)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-amount-out
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :amount-out)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-amount-in
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :amount-in)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-receive-amount
|
||||
:<- [:wallet/swap-proposal-amount-out]
|
||||
:<- [:wallet/swap-asset-to-receive]
|
||||
(fn [[amount-out asset-to-receive]]
|
||||
(let [receive-token-decimals (:decimals asset-to-receive)
|
||||
receive-amount (when amount-out
|
||||
(number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(hex/normalize-hex
|
||||
amount-out))
|
||||
receive-token-decimals))
|
||||
receive-amount (when amount-out
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed receive-amount
|
||||
(min receive-token-decimals
|
||||
constants/min-token-decimals-to-display))))]
|
||||
(or receive-amount 0))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-pay-amount
|
||||
:<- [:wallet/swap-proposal-amount-in]
|
||||
:<- [:wallet/swap-asset-to-pay]
|
||||
(fn [[amount-in asset-to-pay]]
|
||||
(let [pay-token-decimals (:decimals asset-to-pay)
|
||||
pay-amount (when amount-in
|
||||
(number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(hex/normalize-hex
|
||||
amount-in))
|
||||
pay-token-decimals))
|
||||
pay-amount (when amount-in
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed pay-amount
|
||||
(min pay-token-decimals
|
||||
constants/min-token-decimals-to-display))))]
|
||||
(or pay-amount 0))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-provider
|
||||
:<- [:wallet/swap-proposal]
|
||||
(fn [swap-proposal]
|
||||
(let [bridge-name (:bridge-name swap-proposal)
|
||||
provider-key (keyword (string/lower-case bridge-name))]
|
||||
(get constants/swap-providers provider-key))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-approval-required
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :approval-required)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-approval-amount-required
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :approval-amount-required)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-estimated-time
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :estimated-time)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
:<- [:wallet/current-viewing-account]
|
||||
:<- [:wallet/swap-proposal]
|
||||
:<- [:profile/currency]
|
||||
:<- [:profile/currency-symbol]
|
||||
(fn [[account swap-proposal currency currency-symbol] [_ token-symbol-for-fees]]
|
||||
(when token-symbol-for-fees
|
||||
(let [tokens (:tokens account)
|
||||
token-for-fees (first (filter #(= (string/lower-case (:symbol %))
|
||||
(string/lower-case token-symbol-for-fees))
|
||||
tokens))
|
||||
fee-in-native-token (send-utils/calculate-full-route-gas-fee [swap-proposal])
|
||||
fee-in-crypto-formatted (utils/get-standard-crypto-format
|
||||
token-for-fees
|
||||
fee-in-native-token)
|
||||
fee-in-fiat (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance fee-in-native-token
|
||||
:token token-for-fees})
|
||||
fee-formatted (utils/get-standard-fiat-format
|
||||
fee-in-crypto-formatted
|
||||
currency-symbol
|
||||
fee-in-fiat)]
|
||||
fee-formatted))))
|
||||
|
||||
@@ -16,27 +16,6 @@
|
||||
:popular? true
|
||||
:token? false}})
|
||||
|
||||
(def ^:private accounts-with-tokens
|
||||
{:0x1 {:tokens [{:symbol "ETH"
|
||||
:balances-per-chain {1 {:raw-balance "100"}}
|
||||
:market-values-per-currency {:usd {:price 10000}}}
|
||||
{:symbol "SNT"
|
||||
:balances-per-chain {1 {:raw-balance "100"}}
|
||||
:market-values-per-currency {:usd {:price 10000}}}]
|
||||
:network-preferences-names #{}
|
||||
:customization-color nil
|
||||
:operable? true
|
||||
:operable :fully
|
||||
:address "0x1"}
|
||||
:0x2 {:tokens [{:symbol "SNT"
|
||||
:balances-per-chain {1 {:raw-balance "200"}}
|
||||
:market-values-per-currency {:usd {:price 10000}}}]
|
||||
:network-preferences-names #{}
|
||||
:customization-color nil
|
||||
:operable? true
|
||||
:operable :partially
|
||||
:address "0x2"}})
|
||||
|
||||
(def networks
|
||||
{:mainnet-network
|
||||
{:full-name "Mainnet"
|
||||
@@ -131,19 +110,7 @@
|
||||
:token-list-id ""
|
||||
:built-on "ETH"
|
||||
:verified true}
|
||||
:network (networks :mainnet-network)
|
||||
:swap-proposal {:amount-out "0x10000"
|
||||
:amount-in "0x10000"
|
||||
:approval-required true
|
||||
:approval-amount-required "0x10000"
|
||||
:gas-amount "25000"
|
||||
:gas-fees {:max-fee-per-gas-medium "4"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
:error-response "Error"
|
||||
:loading-fees? false
|
||||
:loading-swap-proposal? false
|
||||
:max-slippage 0.5})
|
||||
:network nil})
|
||||
|
||||
(h/deftest-sub :wallet/swap
|
||||
[sub-name]
|
||||
@@ -193,91 +160,3 @@
|
||||
(assoc :currencies currencies)
|
||||
(assoc-in [:wallet :ui :swap] swap-data)))
|
||||
(is (match? {:crypto "1 SNT" :fiat "$0.03"} (rf/sub [sub-name 1])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-network
|
||||
[sub-name]
|
||||
(testing "Return the current swap network"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? (swap-data :network) (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-error-response
|
||||
[sub-name]
|
||||
(testing "Return the swap error response"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? (swap-data :error-response) (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-max-slippage
|
||||
[sub-name]
|
||||
(testing "Return the max slippage for the swap"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? 0.5 (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-loading-fees?
|
||||
[sub-name]
|
||||
(testing "Return if swap is loading fees"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (false? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-loading-swap-proposal?
|
||||
[sub-name]
|
||||
(testing "Return if swap is loading the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (false? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal
|
||||
[sub-name]
|
||||
(testing "Return the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? (swap-data :swap-proposal) (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal-amount-out
|
||||
[sub-name]
|
||||
(testing "Return the amount out in the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? "0x10000" (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal-approval-required
|
||||
[sub-name]
|
||||
(testing "Return if approval is required in the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (true? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal-approval-amount-required
|
||||
[sub-name]
|
||||
(testing "Return the approval amount required in the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? "0x10000" (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
[sub-name]
|
||||
(testing "wallet send fee calculated and formatted in fiat"
|
||||
(swap! rf-db/app-db
|
||||
#(-> %
|
||||
(assoc-in [:wallet :accounts] accounts-with-tokens)
|
||||
(assoc-in [:wallet :current-viewing-account-address] "0x1")
|
||||
(assoc-in [:wallet :ui :swap] swap-data)
|
||||
(assoc-in [:currencies] currencies)
|
||||
(assoc-in [:profile/profile :currency] :usd)
|
||||
(assoc-in [:profile/profile :currency-symbol] "$")))
|
||||
|
||||
(let [token-symbol-for-fees "ETH"
|
||||
result (rf/sub [sub-name token-symbol-for-fees])]
|
||||
(is (match? result "$1.00")))))
|
||||
|
||||
@@ -202,6 +202,11 @@
|
||||
[gas gas-price]
|
||||
(.times ^js (bignumber gas) ^js (bignumber gas-price)))
|
||||
|
||||
(defn crypto->fiat
|
||||
[crypto fiat-price]
|
||||
(when-let [^js bn (bignumber crypto)]
|
||||
(.times bn ^js (bignumber fiat-price))))
|
||||
|
||||
(defn percent-change
|
||||
[from to]
|
||||
(let [^js bnf (bignumber from)
|
||||
@@ -216,12 +221,6 @@
|
||||
(when-let [^js bn (bignumber n)]
|
||||
(.round bn decimals)))
|
||||
|
||||
(defn crypto->fiat
|
||||
[crypto fiat-price]
|
||||
(when-let [^js bn (bignumber crypto)]
|
||||
(-> (.times bn ^js (bignumber fiat-price))
|
||||
(with-precision 2))))
|
||||
|
||||
(defn sufficient-funds?
|
||||
[^js amount ^js balance]
|
||||
(when (and amount balance)
|
||||
|
||||
@@ -15,17 +15,6 @@
|
||||
(/ (Math/round (* n scale))
|
||||
scale)))
|
||||
|
||||
(defn convert-to-whole-number
|
||||
"Converts a fractional `amount` to its corresponding whole number representation
|
||||
by dividing it by 10 raised to the power of `decimals`. This is often used in financial
|
||||
calculations where amounts are stored in their smallest units (e.g., cents) and need
|
||||
to be converted to their whole number equivalents (e.g., dollars).
|
||||
|
||||
Example usage:
|
||||
(convert-to-whole-number 12345 2) ; => 123.45"
|
||||
[amount decimals]
|
||||
(/ amount (Math/pow 10 decimals)))
|
||||
|
||||
(defn parse-int
|
||||
"Parses `n` as an integer. Defaults to zero or `default` instead of NaN."
|
||||
([n]
|
||||
|
||||
@@ -3,26 +3,6 @@
|
||||
[cljs.test :refer [deftest is testing]]
|
||||
[utils.number]))
|
||||
|
||||
(deftest convert-to-whole-number-test
|
||||
(testing "correctly converts fractional amounts to whole numbers"
|
||||
(is (= 123.45 (utils.number/convert-to-whole-number 12345 2)))
|
||||
(is (= 1.2345 (utils.number/convert-to-whole-number 12345 4)))
|
||||
(is (= 12345.0 (utils.number/convert-to-whole-number 1234500 2)))
|
||||
(is (= 0.123 (utils.number/convert-to-whole-number 123 3)))
|
||||
(is (= 1000.0 (utils.number/convert-to-whole-number 1000000 3))))
|
||||
|
||||
(testing "handles zero decimals"
|
||||
(is (= 12345 (utils.number/convert-to-whole-number 12345 0))))
|
||||
|
||||
(testing "handles negative amounts"
|
||||
(is (= -123.45 (utils.number/convert-to-whole-number -12345 2)))
|
||||
(is (= -1.2345 (utils.number/convert-to-whole-number -12345 4)))
|
||||
(is (= -0.123 (utils.number/convert-to-whole-number -123 3))))
|
||||
|
||||
(testing "handles zero amount"
|
||||
(is (= 0 (utils.number/convert-to-whole-number 0 2)))
|
||||
(is (= 0 (utils.number/convert-to-whole-number 0 0)))))
|
||||
|
||||
(deftest parse-int-test
|
||||
(testing "defaults to zero"
|
||||
(is (= 0 (utils.number/parse-int nil))))
|
||||
|
||||
@@ -88,9 +88,3 @@
|
||||
[url]
|
||||
(when (string? url)
|
||||
(string/replace url #"^https?://" "")))
|
||||
|
||||
(defn valid-amount-for-token-decimals?
|
||||
[token-decimals amount-text]
|
||||
(let [regex-pattern (str "^\\d*\\.?\\d{0," token-decimals "}$")
|
||||
regex (re-pattern regex-pattern)]
|
||||
(re-matches regex amount-text)))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.184.52",
|
||||
"commit-sha1": "81cfce709e8d123eb1956b87f8e0f19dc47c122c",
|
||||
"src-sha256": "0hna30ms4ccxmi20l5v36y84pva1s4jjkqg11whwmdjgw75d0fan"
|
||||
"version": "83f9ec909286cbebe1f68437aa51489922f59315",
|
||||
"commit-sha1": "83f9ec909286cbebe1f68437aa51489922f59315",
|
||||
"src-sha256": "0v6ad2cbmzmwdcpnlbw7maljir22939lbj5bk6agnxhfpacad490"
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"add-bootnode": "Add bootnode",
|
||||
"add-contact": "Add contact",
|
||||
"add-custom-token": "Add custom token",
|
||||
"add-existing-status-profile": "Add existing Status profile",
|
||||
"add-favourite": "Add favourite",
|
||||
"add-mailserver": "Add Status node",
|
||||
"add-me-to-your-contacts": "Please add me to your contacts",
|
||||
@@ -2301,7 +2302,6 @@
|
||||
"slow": "Slow",
|
||||
"something-about-you": "Something about you",
|
||||
"something-went-wrong": "Something went wrong",
|
||||
"something-went-wrong-please-try-again-later": "Something went wrong, please try again later",
|
||||
"soon": "Soon",
|
||||
"sort-communities": "Sort communities",
|
||||
"special-characters": "Special characters",
|
||||
@@ -2312,8 +2312,6 @@
|
||||
"specify-symbol": "Specify a symbol",
|
||||
"spender-contract": "Spender contract",
|
||||
"spending-cap": "Spending cap",
|
||||
"spending-cap-failed": "Spending cap failed: {{amount}} {{token-symbol}} for {{provider-name}} in {{account-name}}",
|
||||
"spending-cap-set": "Spending cap set: {{amount}} {{token-symbol}} for {{provider-name}} in {{account-name}}",
|
||||
"start-chat": "Start chat",
|
||||
"start-conversation": "Start conversation",
|
||||
"start-group-chat": "Start group chat",
|
||||
@@ -2368,9 +2366,6 @@
|
||||
"sun": "Sun",
|
||||
"swap": "Swap",
|
||||
"swap-details": "Swap details",
|
||||
"swap-failed": "Swap failed",
|
||||
"swapped-to": "Swapped {{pay-amount}} {{pay-token-symbol}} to {{receive-amount}} {{receive-token-symbol}}",
|
||||
"swapping-to": "Swapping {{pay-amount}} {{pay-token-symbol}} to {{receive-amount}} {{receive-token-symbol}}",
|
||||
"swaps-powered-by": "Swaps powered by {{provider}}",
|
||||
"switch-to-simple-interface": "Switch to simple interface",
|
||||
"symbol": "Symbol",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"add-bootnode": "Bootnodeを追加",
|
||||
"add-contact": "連絡先を追加",
|
||||
"add-custom-token": "カスタムトークンを追加",
|
||||
"add-existing-status-profile": "既存のStatusプロフィールを追加する",
|
||||
"add-favourite": "お気に入りに追加する",
|
||||
"add-mailserver": "Statusノードを追加",
|
||||
"add-me-to-your-contacts": "連絡先に追加してください",
|
||||
|
||||
Reference in New Issue
Block a user