diff --git a/app/src/external/res/xml/network_security_config.xml b/app/src/external/res/xml/network_security_config.xml
new file mode 100644
index 0000000000..894912ac61
--- /dev/null
+++ b/app/src/external/res/xml/network_security_config.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
index 4f9ab200f1..e99dcef57b 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
@@ -37,6 +37,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.Optimism, Blockchain.OptimismTestnet -> R.drawable.ic_optimism_no_color
Blockchain.Dash -> R.drawable.ic_dash_no_color
Blockchain.Kaspa -> R.drawable.ic_kaspa_no_color
+ Blockchain.TON, Blockchain.TONTestnet -> R.drawable.ic_ton_no_color
else -> R.drawable.ic_tangem_logo
}
}
diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt
index 9136094e8b..fd5bf29aa9 100644
--- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt
+++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt
@@ -50,7 +50,7 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator {
is WalletDataModel.SameCurrencyTransactionInProgress,
is WalletDataModel.TransactionInProgress,
is WalletDataModel.NoAccount,
- -> if (walletData.isCustom || walletData.fiatRate == null) {
+ -> if (walletData.isCustom && walletData.fiatRate == null) {
TotalFiatBalanceStatus.Error
} else {
TotalFiatBalanceStatus.Loaded
@@ -65,7 +65,7 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator {
private fun Sequence.calculateTotalFiatAmount(): BigDecimal? {
return this
- .filterNot { it.isCustom }
+ .filterNot { it.isCustom && it.fiatRate == null }
.map { walletData ->
walletData.fiatRate
?.takeUnless { walletData.status.isErrorStatus }
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt
index 5ca27d5e6c..00342aaddb 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt
@@ -65,6 +65,10 @@ sealed class TransactionExtrasAction : SendScreenActionUi {
sealed class XrpDestinationTag : TransactionExtrasAction() {
data class HandleUserInput(val data: String) : XrpDestinationTag()
}
+
+ sealed class TonMemo : TransactionExtrasAction() {
+ data class HandleUserInput(val data: String) : TonMemo()
+ }
}
sealed class AddressPayIdVerifyAction : SendScreenAction {
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt
index b87cc3c49b..0a528bd856 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt
@@ -4,6 +4,7 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
+import com.tangem.blockchain.blockchains.ton.TonTransactionExtras
import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.BlockchainSdkError
@@ -170,6 +171,7 @@ private fun sendTransaction(
transactionExtras.xrpDestinationTag?.tag?.let {
txData = txData.copy(extras = XrpTransactionBuilder.XrpTransactionExtras(it))
}
+ transactionExtras.tonMemoState?.memo?.let { txData = txData.copy(extras = TonTransactionExtras(it)) }
scope.launch {
val updateWalletResult = walletManager.safeUpdate()
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt
index 583e9f0439..a62a6e361e 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt
@@ -6,11 +6,13 @@ import com.tangem.tap.features.send.redux.SendScreenAction
import com.tangem.tap.features.send.redux.TransactionExtrasAction.BinanceMemo
import com.tangem.tap.features.send.redux.TransactionExtrasAction.Prepare
import com.tangem.tap.features.send.redux.TransactionExtrasAction.Release
+import com.tangem.tap.features.send.redux.TransactionExtrasAction.TonMemo
import com.tangem.tap.features.send.redux.TransactionExtrasAction.XlmMemo
import com.tangem.tap.features.send.redux.TransactionExtrasAction.XrpDestinationTag
import com.tangem.tap.features.send.redux.states.BinanceMemoState
import com.tangem.tap.features.send.redux.states.InputViewValue
import com.tangem.tap.features.send.redux.states.SendState
+import com.tangem.tap.features.send.redux.states.TonMemoState
import com.tangem.tap.features.send.redux.states.TransactionExtraError
import com.tangem.tap.features.send.redux.states.TransactionExtrasState
import com.tangem.tap.features.send.redux.states.XlmMemoState
@@ -28,6 +30,7 @@ class TransactionExtrasReducer : SendInternalReducer {
is XlmMemo -> handleXlmMemo(action, sendState, sendState.transactionExtrasState)
is BinanceMemo -> handleBinanceMemo(action, sendState, sendState.transactionExtrasState)
is XrpDestinationTag -> handleXrpTag(action, sendState, sendState.transactionExtrasState)
+ is TonMemo -> handleTonMemo(action, sendState, sendState.transactionExtrasState)
else -> sendState
}
}
@@ -56,6 +59,7 @@ class TransactionExtrasReducer : SendInternalReducer {
}
Blockchain.Stellar -> TransactionExtrasState(xlmMemo = XlmMemoState())
Blockchain.Binance -> TransactionExtrasState(binanceMemo = BinanceMemoState())
+ Blockchain.TON, Blockchain.TONTestnet -> TransactionExtrasState(tonMemoState = TonMemoState())
else -> emptyResult
}
return updateLastState(sendState.copy(transactionExtrasState = result), result)
@@ -140,4 +144,15 @@ class TransactionExtrasReducer : SendInternalReducer {
}
return updateLastState(sendState.copy(transactionExtrasState = result), result)
}
+
+ private fun handleTonMemo(action: TonMemo, sendState: SendState, infoState: TransactionExtrasState): SendState {
+ val result = when (action) {
+ is TonMemo.HandleUserInput -> {
+ val memo = action.data
+ val input = InputViewValue(memo, true)
+ infoState.copy(tonMemoState = TonMemoState(input, memo))
+ }
+ }
+ return updateLastState(sendState.copy(transactionExtrasState = result), result)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt
index 10ffa2dc51..3ff920281d 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt
@@ -30,6 +30,7 @@ data class TransactionExtrasState(
val xlmMemo: XlmMemoState? = null,
val binanceMemo: BinanceMemoState? = null,
val xrpDestinationTag: XrpDestinationTagState? = null,
+ val tonMemoState: TonMemoState? = null,
) : IdStateHolder {
override val stateId: StateId = StateId.TRANSACTION_EXTRAS
}
@@ -98,6 +99,12 @@ data class XrpDestinationTagState(
}
}
+data class TonMemoState(
+ val viewFieldValue: InputViewValue = InputViewValue(""),
+ val memo: String? = null,
+ val error: TransactionExtraError? = null,
+)
+
enum class TransactionExtraError {
INVALID_DESTINATION_TAG,
INVALID_XLM_MEMO,
diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt
index ecc6d5d00e..519556af28 100644
--- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt
@@ -60,7 +60,6 @@ import com.tangem.tap.mainScope
import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.FragmentSendBinding
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
@@ -173,6 +172,15 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
}
.onEach { store.dispatch(TransactionExtrasAction.BinanceMemo.HandleUserInput(it)) }
.launchIn(mainScope)
+
+ etTonMemo.inputtedTextAsFlow()
+ .debounce(400)
+ .filter {
+ val info = store.state.sendState.transactionExtrasState
+ info.tonMemoState?.viewFieldValue?.value != it
+ }
+ .onEach { store.dispatch(TransactionExtrasAction.TonMemo.HandleUserInput(it)) }
+ .launchIn(mainScope)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -331,7 +339,6 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
}
}
-@ExperimentalCoroutinesApi
fun EditText.inputtedTextAsFlow(): Flow = callbackFlow {
val watcher = addTextChangedListener { editable -> trySend(editable?.toString() ?: "") }
awaitClose { removeTextChangedListener(watcher) }
diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/KaspaWarningDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/KaspaWarningDialog.kt
index 52d29b6d91..5e9f50747f 100644
--- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/KaspaWarningDialog.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/KaspaWarningDialog.kt
@@ -2,7 +2,6 @@ package com.tangem.tap.features.send.ui.dialogs
import android.content.Context
import androidx.appcompat.app.AlertDialog
-import com.tangem.tap.common.extensions.dispatchDialogHide
import com.tangem.tap.features.send.redux.SendAction
import com.tangem.tap.store
import com.tangem.wallet.R
@@ -22,7 +21,7 @@ object KaspaWarningDialog {
dialog.onOk()
}
setOnDismissListener {
- store.dispatchDialogHide()
+ store.dispatch(SendAction.Dialog.Hide)
}
}
.create()
diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt
index 91376439fc..e250ad075e 100644
--- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt
@@ -46,8 +46,8 @@ import com.tangem.wallet.R
/**
[REDACTED_AUTHOR]
*/
-class SendStateSubscriber(fragment: BaseStoreFragment) :
- FragmentStateSubscriber(fragment) {
+@Suppress("LargeClass")
+class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber(fragment) {
private var dialog: Dialog? = null
@@ -79,6 +79,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) :
showView(xlmMemoContainer, infoState.xlmMemo)
showView(xrpDestinationTagContainer, infoState.xrpDestinationTag)
showView(binanceMemoContainer, infoState.binanceMemo)
+ showView(tonMemoContainer, infoState.tonMemoState)
infoState.xlmMemo?.let {
if (!it.viewFieldValue.isFromUserInput) etXlmMemo.setText(it.viewFieldValue.value)
@@ -115,6 +116,16 @@ class SendStateSubscriber(fragment: BaseStoreFragment) :
etBinanceMemo.setText(it.viewFieldValue.value)
}
}
+ infoState.tonMemoState?.let {
+ if (infoState.tonMemoState.error != null) {
+ tilTonMemo.error = fg.getText(R.string.send_extras_error_invalid_memo)
+ } else {
+ tilBinanceMemo.error = null
+ }
+ if (!it.viewFieldValue.isFromUserInput) {
+ etTonMemo.setText(it.viewFieldValue.value)
+ }
+ }
}
private fun handleSendScreen(fg: SendFragment, state: SendState) = with(fg.binding) {
diff --git a/app/src/main/res/drawable/ic_ton_no_color.xml b/app/src/main/res/drawable/ic_ton_no_color.xml
new file mode 100644
index 0000000000..c3d5d856db
--- /dev/null
+++ b/app/src/main/res/drawable/ic_ton_no_color.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/layout/layout_send_address_payid.xml b/app/src/main/res/layout/layout_send_address_payid.xml
index b16e59b974..f16f48a119 100644
--- a/app/src/main/res/layout/layout_send_address_payid.xml
+++ b/app/src/main/res/layout/layout_send_address_payid.xml
@@ -228,6 +228,37 @@
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
index f3d1e037fd..9c11cb37dc 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
@@ -33,6 +33,7 @@ fun getActiveIconRes(blockchainId: String): Int {
"OPTIMISM", "OPTIMISM/test" -> R.drawable.img_optimism_22
"DASH" -> R.drawable.img_dash_22
"KAS" -> R.drawable.img_kaspa_22
+ "The-Open-Network", "The-Open-Network/test" -> R.drawable.img_ton_22
else -> R.drawable.ic_alert_24
}
}
@@ -72,6 +73,7 @@ fun getActiveIconResByCoinId(coinId: String, networkId: String): Int {
"kusama" -> R.drawable.img_kusama_22
"dash" -> R.drawable.img_dash_22
"kaspa" -> R.drawable.img_kaspa_22
+ "ton" -> R.drawable.img_ton_22
else -> R.drawable.ic_alert_24
}
}
\ No newline at end of file
diff --git a/core/ui/src/main/res/drawable/img_ton_22.xml b/core/ui/src/main/res/drawable/img_ton_22.xml
new file mode 100644
index 0000000000..a5eae04964
--- /dev/null
+++ b/core/ui/src/main/res/drawable/img_ton_22.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index d1867f7c33..67b386e4e9 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -44,11 +44,11 @@ platform :android do
})
end
- desc "Build internal and release APKs"
+ desc "Build external and release APKs"
lane :build do |options|
gradle(
task: "clean assemble",
- build_type: "Internal",
+ build_type: "External",
properties: {
'versionCode' => options[:versionCode],
'versionName' => options[:versionName],
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt
index b955369d7e..cdca70f863 100644
--- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt
@@ -244,7 +244,7 @@ internal class SwapInteractorImpl @Inject constructor(
return repository.getTangemFee()
}
- fun getTokenDecimals(token: Currency): Int {
+ private fun getTokenDecimals(token: Currency): Int {
return if (token is Currency.NonNativeToken) {
token.decimalCount
} else {
@@ -351,15 +351,15 @@ internal class SwapInteractorImpl @Inject constructor(
swapStateData = null,
formattedFee = null,
)
- return updatePermissionState(
+ val quotesState = updatePermissionState(
networkId = networkId,
fromToken = fromToken,
quotesLoadedState = swapState,
- ).copy(
- preparedSwapConfigState = PreparedSwapConfigState(
+ )
+ return quotesState.copy(
+ preparedSwapConfigState = quotesState.preparedSwapConfigState.copy(
isAllowedToSpend = isAllowedToSpend,
isBalanceEnough = isBalanceWithoutFeeEnough,
- isFeeEnough = true,
),
)
} else {
@@ -533,7 +533,14 @@ internal class SwapInteractorImpl @Inject constructor(
decimals = transactionManager.getNativeTokenDecimals(networkId),
currency = userWalletManager.getNetworkCurrency(networkId),
) + feeFiat
+ val isFeeEnough = checkFeeIsEnough(
+ fee = feeData.fee.value,
+ spendAmount = SwapAmount.zeroSwapAmount(),
+ networkId = networkId,
+ fromToken = fromToken,
+ )
return quotesLoadedState.copy(
+ fee = formattedFee,
permissionState = PermissionDataState.PermissionReadyForRequest(
currency = fromToken.symbol,
amount = INFINITY_SYMBOL,
@@ -546,6 +553,9 @@ internal class SwapInteractorImpl @Inject constructor(
approveModel = transactionData,
),
),
+ preparedSwapConfigState = quotesLoadedState.preparedSwapConfigState.copy(
+ isFeeEnough = isFeeEnough,
+ ),
)
}
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt
index 342ce251e7..c37e6fbc96 100644
--- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt
@@ -6,7 +6,14 @@ import java.math.BigDecimal
data class SwapAmount(
val value: BigDecimal,
val decimals: Int,
-)
+) {
+
+ companion object {
+ fun zeroSwapAmount(): SwapAmount {
+ return SwapAmount(BigDecimal.ZERO, 0)
+ }
+ }
+}
fun SwapAmount.formatToUIRepresentation(): String {
return value.toFormattedString(decimals = decimals)
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PreparedSwapConfigState.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PreparedSwapConfigState.kt
index 29515eef16..8b9f1c963b 100644
--- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PreparedSwapConfigState.kt
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PreparedSwapConfigState.kt
@@ -1,5 +1,12 @@
package com.tangem.feature.swap.domain.models.domain
+/**
+ * Prepared swap config state that contains flags to determine
+ *
+ * @property isAllowedToSpend shows is token allowed to spend
+ * @property isBalanceEnough shows is balance of token enough
+ * @property isFeeEnough shows is amount of main coin enough for fee
+ */
data class PreparedSwapConfigState(
val isAllowedToSpend: Boolean,
val isBalanceEnough: Boolean,
diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml
index 940a09f956..f6c1447110 100644
--- a/gradle/dependencies.toml
+++ b/gradle/dependencies.toml
@@ -71,9 +71,9 @@ kotlinSerialization = "1.4.1"
# endregion Other libraries
# region Tangem
-tangemBlockchainSdk = "develop-185"
+tangemBlockchainSdk = "develop-189"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
-tangemCardSdk = "develop-208"
+tangemCardSdk = "develop-209"
# tangemCardSdk = "0.0.1" # Keep it! - used for local builds
# endregion Tangem