diff --git a/build.gradle b/build.gradle index feb498a264..637bbc5c48 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { // App version - versionName = '9.1.1' - versionCode = 166 + versionName = '9.1.2' + versionCode = 167 applicationId = "io.novafoundation.nova" releaseApplicationSuffix = "market" diff --git a/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt b/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt index 7ec587e3f7..aaae01c294 100644 --- a/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt +++ b/common/src/main/java/io/novafoundation/nova/common/utils/KotlinExt.kt @@ -142,6 +142,18 @@ fun ByteArray.startsWith(prefix: ByteArray): Boolean { return true } +fun ByteArray.endsWith(suffix: ByteArray): Boolean { + if (suffix.size > size) return false + + val offset = size - suffix.size + + suffix.forEachIndexed { index, byte -> + if (get(offset + index) != byte) return false + } + + return true +} + fun ByteArray.windowed(windowSize: Int): List { require(windowSize > 0) { "Window size should be positive" diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 6cfe0b4586..26d5a6471e 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -2,7 +2,7 @@ During swap execution intermediate receive amount is %s which is less than minimum balance of %s. Try specifying larger swap amount. - You don\'t hae enough balance to pay network fee of %s. Current balance is %s + You don\'t have enough balance to pay network fee of %s. Current balance is %s sec @@ -55,7 +55,7 @@ Select network for buying %s Select network for receiving %s Select network for sending %s - Select network for swaping %s + Select network for swapping %s Tokens Networks diff --git a/common/src/test/java/io/novafoundation/nova/common/utils/KotlinExtTest.kt b/common/src/test/java/io/novafoundation/nova/common/utils/KotlinExtTest.kt new file mode 100644 index 0000000000..7f88b454d4 --- /dev/null +++ b/common/src/test/java/io/novafoundation/nova/common/utils/KotlinExtTest.kt @@ -0,0 +1,29 @@ +package io.novafoundation.nova.common.utils + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class KotlinExtTest { + + @Test + fun `endsWith should return false for suffix bigger than content`() { + assertFalse(byteArrayOf(0, 1).endsWith(byteArrayOf(0, 1, 2))) + } + + @Test + fun `endsWith should return true for suffix equal to the content`() { + assertTrue(byteArrayOf(0, 1, 2).endsWith(byteArrayOf(0, 1, 2))) + } + + @Test + fun `endsWith should return true for correct suffix`() { + assertTrue(byteArrayOf(0, 1, 2).endsWith(byteArrayOf(1, 2))) + } + + @Test + fun `endsWith should return true for incorrect suffix`() { + assertFalse(byteArrayOf(0, 1, 2, 3).endsWith(byteArrayOf(1, 2))) + assertFalse(byteArrayOf(0, 1, 2, 3).endsWith(byteArrayOf(2))) + } +} diff --git a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt index 32b8034913..bb2a289ee2 100644 --- a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt +++ b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt @@ -5,8 +5,10 @@ import io.novafoundation.nova.common.address.AddressIconGenerator import io.novafoundation.nova.common.address.AddressModel import io.novafoundation.nova.common.utils.asHexString import io.novafoundation.nova.common.utils.bigIntegerFromHex +import io.novafoundation.nova.common.utils.endsWith import io.novafoundation.nova.common.utils.intFromHex import io.novafoundation.nova.common.utils.singleReplaySharedFlow +import io.novafoundation.nova.common.utils.startsWith import io.novafoundation.nova.common.validation.EmptyValidationSystem import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi @@ -49,7 +51,6 @@ import io.novasama.substrate_sdk_android.runtime.extrinsic.Nonce import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.SendableExtrinsic import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.SignerPayloadRaw import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.fromHex -import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.fromUtf8 import io.novasama.substrate_sdk_android.wsrpc.request.runtime.chain.RuntimeVersion import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -178,11 +179,7 @@ class PolkadotExternalSignInteractor( val accountId = signBytesPayload.address.anyAddressToAccountId() val signer = resolveWalletSigner() - val payload = runCatching { - SignerPayloadRaw.fromHex(signBytesPayload.data, accountId) - }.getOrElse { - SignerPayloadRaw.fromUtf8(signBytesPayload.data, accountId) - } + val payload = SignerPayloadRaw.fromUnsafeString(signBytesPayload.data, accountId) val signature = signer.signRaw(payload).asHexString() return SignedResult(signature, modifiedTransaction = null) @@ -244,6 +241,26 @@ class PolkadotExternalSignInteractor( ) } + private fun SignerPayloadRaw.Companion.fromUnsafeString(data: String, signer: AccountId): SignerPayloadRaw { + val unsafeMessage = decodeSigningMessage(data) + val safeMessage = protectSigningMessage(unsafeMessage) + + return SignerPayloadRaw(safeMessage, signer) + } + + private fun decodeSigningMessage(data: String): ByteArray { + return kotlin.runCatching { data.fromHex() }.getOrElse { data.encodeToByteArray() } + } + + private fun protectSigningMessage(message: ByteArray): ByteArray { + val prefix = "".encodeToByteArray() + val suffix = "".encodeToByteArray() + + if (message.startsWith(prefix) && message.endsWith(suffix)) return message + + return prefix + message + suffix + } + private suspend fun PolkadotSignPayload.Json.actualMetadataHash(chain: Chain, signer: NovaSigner): ActualMetadataHash { // If a dapp haven't declared a permission to modify extrinsic - return whatever metadataHash present in payload if (withSignedTransaction != true) { diff --git a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/blockchain/assets/events/utility/NativeAssetEventDetector.kt b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/blockchain/assets/events/utility/NativeAssetEventDetector.kt index 3e01eff0c1..36e4da3e98 100644 --- a/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/blockchain/assets/events/utility/NativeAssetEventDetector.kt +++ b/feature-wallet-impl/src/main/java/io/novafoundation/nova/feature_wallet_impl/data/network/blockchain/assets/events/utility/NativeAssetEventDetector.kt @@ -12,6 +12,7 @@ class NativeAssetEventDetector : AssetEventDetector { override fun detectDeposit(event: GenericEvent.Instance): DepositEvent? { return detectMinted(event) + ?: detectBalancesDeposit(event) } private fun detectMinted(event: GenericEvent.Instance): DepositEvent? { @@ -24,4 +25,15 @@ class NativeAssetEventDetector : AssetEventDetector { amount = bindNumber(amount) ) } + + private fun detectBalancesDeposit(event: GenericEvent.Instance): DepositEvent? { + if (!event.instanceOf(Modules.BALANCES, "Deposit")) return null + + val (who, amount) = event.arguments + + return DepositEvent( + destination = bindAccountId(who), + amount = bindNumber(amount) + ) + } }