diff --git a/app/src/androidTest/kotlin/wallet/android/app/tokens/TestValidateTokenAddress.kt b/app/src/androidTest/kotlin/wallet/android/app/tokens/TestValidateTokenAddress.kt index cecc6e3fe..60cf99fe8 100644 --- a/app/src/androidTest/kotlin/wallet/android/app/tokens/TestValidateTokenAddress.kt +++ b/app/src/androidTest/kotlin/wallet/android/app/tokens/TestValidateTokenAddress.kt @@ -1,11 +1,5 @@ package wallet.android.app.tokens -import com.gemwallet.android.blockchain.clients.aptos.AptosGetTokenClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmGetTokenClient -import com.gemwallet.android.blockchain.clients.solana.SolanaTokenClient -import com.gemwallet.android.blockchain.clients.sui.SuiGetTokenClient -import com.gemwallet.android.blockchain.clients.ton.TonGetTokenClient -import com.gemwallet.android.blockchain.clients.tron.TronGetTokenClient import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue import org.junit.Test diff --git a/app/src/main/assets/swap/orca.svg b/app/src/main/assets/swap/orca.svg deleted file mode 100644 index 21fcf7fdd..000000000 --- a/app/src/main/assets/swap/orca.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/app/src/main/kotlin/com/gemwallet/android/data/password/PreferencePasswordStore.kt b/app/src/main/kotlin/com/gemwallet/android/data/password/PreferencePasswordStore.kt index a558e23f5..69091f677 100644 --- a/app/src/main/kotlin/com/gemwallet/android/data/password/PreferencePasswordStore.kt +++ b/app/src/main/kotlin/com/gemwallet/android/data/password/PreferencePasswordStore.kt @@ -8,6 +8,7 @@ import androidx.security.crypto.MasterKey import com.gemwallet.android.blockchain.operators.PasswordStore import com.gemwallet.android.math.toHexString import java.security.SecureRandom +import androidx.core.content.edit class PreferencePasswordStore( private val context: Context, @@ -18,10 +19,9 @@ class PreferencePasswordStore( override fun createPassword(walletId: String): String { val key = ByteArray(16) random.nextBytes(key) - getStore() - .edit() - .putString(walletId, key.toHexString()) - .commit() + getStore().edit(commit = true) { + putString(walletId, key.toHexString()) + } return key.toHexString() } diff --git a/app/src/main/kotlin/com/gemwallet/android/di/DataModule.kt b/app/src/main/kotlin/com/gemwallet/android/di/DataModule.kt index 7c3d026c9..55d662bc0 100644 --- a/app/src/main/kotlin/com/gemwallet/android/di/DataModule.kt +++ b/app/src/main/kotlin/com/gemwallet/android/di/DataModule.kt @@ -1,83 +1,32 @@ package com.gemwallet.android.di -import com.gemwallet.android.blockchain.RpcClientAdapter -import com.gemwallet.android.blockchain.clients.ActivationTransactionPreloader -import com.gemwallet.android.blockchain.clients.ApprovalTransactionPreloader -import com.gemwallet.android.blockchain.clients.BroadcastClientProxy -import com.gemwallet.android.blockchain.clients.GenericTransferPreloader -import com.gemwallet.android.blockchain.clients.NftTransactionPreloader -import com.gemwallet.android.blockchain.clients.NodeStatusClientProxy -import com.gemwallet.android.blockchain.clients.SignClientProxy -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.algorand.AlgorandBroadcastClient -import com.gemwallet.android.blockchain.clients.algorand.AlgorandNodeStatusClient import com.gemwallet.android.blockchain.clients.algorand.AlgorandSignClient -import com.gemwallet.android.blockchain.clients.algorand.AlgorandSignPreloadClient -import com.gemwallet.android.blockchain.clients.aptos.AptosBroadcastClient -import com.gemwallet.android.blockchain.clients.aptos.AptosNodeStatusClient import com.gemwallet.android.blockchain.clients.aptos.AptosSignClient -import com.gemwallet.android.blockchain.clients.aptos.AptosSignerPreloader -import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinBroadcastClient -import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinNodeStatusClient import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinSignClient -import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinSignerPreloader -import com.gemwallet.android.blockchain.clients.cardano.CardanoBroadcastClient -import com.gemwallet.android.blockchain.clients.cardano.CardanoNodeStatusClient import com.gemwallet.android.blockchain.clients.cardano.CardanoSignClient -import com.gemwallet.android.blockchain.clients.cardano.CardanoSignerPreloaderClient -import com.gemwallet.android.blockchain.clients.cosmos.CosmosBroadcastClient -import com.gemwallet.android.blockchain.clients.cosmos.CosmosNodeStatusClient import com.gemwallet.android.blockchain.clients.cosmos.CosmosSignClient -import com.gemwallet.android.blockchain.clients.cosmos.CosmosSignerPreloader -import com.gemwallet.android.blockchain.clients.ethereum.EvmBroadcastClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmNodeStatusClient import com.gemwallet.android.blockchain.clients.ethereum.EvmSignClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmSignerPreloader -import com.gemwallet.android.blockchain.clients.near.NearBroadcastClient -import com.gemwallet.android.blockchain.clients.near.NearNodeStatusClient +import com.gemwallet.android.blockchain.clients.hyper.HyperCoreSignClient import com.gemwallet.android.blockchain.clients.near.NearSignClient -import com.gemwallet.android.blockchain.clients.near.NearSignerPreloader -import com.gemwallet.android.blockchain.clients.polkadot.PolkadotBroadcastClient -import com.gemwallet.android.blockchain.clients.polkadot.PolkadotNodeStatusClient import com.gemwallet.android.blockchain.clients.polkadot.PolkadotSignClient -import com.gemwallet.android.blockchain.clients.polkadot.PolkadotSignerPreloaderClient -import com.gemwallet.android.blockchain.clients.solana.SolanaBroadcastClient -import com.gemwallet.android.blockchain.clients.solana.SolanaNodeStatusClient import com.gemwallet.android.blockchain.clients.solana.SolanaSignClient -import com.gemwallet.android.blockchain.clients.solana.SolanaSignerPreloader -import com.gemwallet.android.blockchain.clients.stellar.StellarBroadcastClient -import com.gemwallet.android.blockchain.clients.stellar.StellarNodeStatusClient import com.gemwallet.android.blockchain.clients.stellar.StellarSignClient -import com.gemwallet.android.blockchain.clients.stellar.StellarSignPreloadClient -import com.gemwallet.android.blockchain.clients.sui.SuiBroadcastClient -import com.gemwallet.android.blockchain.clients.sui.SuiNodeStatusClient import com.gemwallet.android.blockchain.clients.sui.SuiSignClient -import com.gemwallet.android.blockchain.clients.sui.SuiSignerPreloader -import com.gemwallet.android.blockchain.clients.ton.TonBroadcastClient -import com.gemwallet.android.blockchain.clients.ton.TonNodeStatusClient import com.gemwallet.android.blockchain.clients.ton.TonSignClient -import com.gemwallet.android.blockchain.clients.ton.TonSignerPreloader -import com.gemwallet.android.blockchain.clients.tron.TronBroadcastClient -import com.gemwallet.android.blockchain.clients.tron.TronNodeStatusClient import com.gemwallet.android.blockchain.clients.tron.TronSignClient -import com.gemwallet.android.blockchain.clients.tron.TronSignerPreloader -import com.gemwallet.android.blockchain.clients.xrp.XrpBroadcastClient -import com.gemwallet.android.blockchain.clients.xrp.XrpNodeStatusClient import com.gemwallet.android.blockchain.clients.xrp.XrpSignClient -import com.gemwallet.android.blockchain.clients.xrp.XrpSignerPreloader -import com.gemwallet.android.cases.device.GetDeviceIdCase +import com.gemwallet.android.blockchain.services.BroadcastService +import com.gemwallet.android.blockchain.services.NodeStatusService +import com.gemwallet.android.blockchain.services.SignClientProxy +import com.gemwallet.android.blockchain.services.SignerPreloaderProxy import com.gemwallet.android.cases.device.SyncSubscription import com.gemwallet.android.cases.transactions.SyncTransactions import com.gemwallet.android.data.repositoreis.assets.AssetsRepository import com.gemwallet.android.data.repositoreis.buy.BuyRepository import com.gemwallet.android.data.repositoreis.session.SessionRepository import com.gemwallet.android.data.repositoreis.wallets.WalletsRepository -import com.gemwallet.android.data.services.gemapi.GemApiClient import com.gemwallet.android.ext.available import com.gemwallet.android.ext.toChainType -import com.gemwallet.android.services.SignerPreloaderProxy import com.gemwallet.android.services.SyncService import com.wallet.core.primitives.Chain import com.wallet.core.primitives.ChainType @@ -85,6 +34,7 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.GemGateway import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -94,66 +44,18 @@ object DataModule { @Provides @Singleton fun providesBroadcastProxy( - rpcClients: RpcClientAdapter, - ): BroadcastClientProxy = BroadcastClientProxy( - Chain.available().map { - when (it.toChainType()) { - ChainType.Bitcoin -> BitcoinBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Ethereum -> EvmBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Solana -> SolanaBroadcastClient(it, rpcClients.getClient(Chain.Solana)) - ChainType.Cosmos -> CosmosBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Ton -> TonBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Tron -> TronBroadcastClient(it, rpcClients.getClient(Chain.Tron)) - ChainType.Aptos -> AptosBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Sui -> SuiBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Xrp -> XrpBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Near -> NearBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Algorand -> AlgorandBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Stellar -> StellarBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Polkadot -> PolkadotBroadcastClient(it, rpcClients.getClient(it)) - ChainType.Cardano -> CardanoBroadcastClient(it, rpcClients.getClient(it)) - } - }, + gateway: GemGateway, + ): BroadcastService = BroadcastService( + gateway = gateway, ) @Provides @Singleton fun provideSignerPreloader( - rpcClients: RpcClientAdapter, - gemApiClient: GemApiClient, - sessionRepository: SessionRepository, - getDeviceIdCase: GetDeviceIdCase, + gateway: GemGateway, ): SignerPreloaderProxy { - val preloaders = Chain.available().map { - when (it.toChainType()) { - ChainType.Bitcoin -> BitcoinSignerPreloader(it, rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Ethereum -> EvmSignerPreloader(it, rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Solana -> SolanaSignerPreloader(it, rpcClients.getClient(Chain.Solana), rpcClients.getClient(Chain.Solana), rpcClients.getClient(Chain.Solana)) - ChainType.Cosmos -> CosmosSignerPreloader(it, rpcClients.getClient(it)) - ChainType.Ton -> TonSignerPreloader(it, rpcClients.getClient(it)) - ChainType.Tron -> TronSignerPreloader(it, rpcClients.getClient(it), rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Aptos -> AptosSignerPreloader(it, rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Sui -> SuiSignerPreloader(it, rpcClients.getClient(it)) - ChainType.Xrp -> XrpSignerPreloader(it, rpcClients.getClient(it)) - ChainType.Near -> NearSignerPreloader(it, rpcClients.getClient(it)) - ChainType.Algorand -> AlgorandSignPreloadClient(it, rpcClients.getClient(it)) - ChainType.Stellar -> StellarSignPreloadClient(it, rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Polkadot -> PolkadotSignerPreloaderClient(it, rpcClients.getClient(it), rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Cardano -> CardanoSignerPreloaderClient(it, rpcClients.getClient(it)) - } - } return SignerPreloaderProxy( - gemApiClient = gemApiClient, - sessionRepository = sessionRepository, - getDeviceIdCase = getDeviceIdCase, - nativeTransferClients = preloaders, - tokenTransferClients = preloaders.mapNotNull { it as? TokenTransferPreloader }, - stakeTransactionClients = preloaders.mapNotNull { it as? StakeTransactionPreloader }, - swapTransactionClients = preloaders.mapNotNull { it as? SwapTransactionPreloader }, - approvalTransactionClients = preloaders.mapNotNull { it as? ApprovalTransactionPreloader }, - activatePreloaderClients = preloaders.mapNotNull { it as? ActivationTransactionPreloader }, - genericPreloaderClients = preloaders.mapNotNull { it as? GenericTransferPreloader }, - nftPreloadClients = preloaders.mapNotNull { it as? NftTransactionPreloader }, + gateway = gateway, ) } @@ -178,6 +80,7 @@ object DataModule { ChainType.Stellar -> StellarSignClient(it) ChainType.Polkadot -> PolkadotSignClient(it) ChainType.Cardano -> CardanoSignClient(it) + ChainType.HyperCore -> HyperCoreSignClient(it) } }, ) @@ -185,28 +88,9 @@ object DataModule { @Singleton @Provides fun provideNodeStatusClient( - rpcClients: RpcClientAdapter, - ): NodeStatusClientProxy { - return NodeStatusClientProxy( - Chain.available().map { - when (it.toChainType()) { - ChainType.Ethereum -> EvmNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Bitcoin -> BitcoinNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Solana -> SolanaNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Cosmos -> CosmosNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Ton -> TonNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Tron -> TronNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Aptos -> AptosNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Sui -> SuiNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Xrp -> XrpNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Near -> NearNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Algorand -> AlgorandNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Stellar -> StellarNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Polkadot -> PolkadotNodeStatusClient(it, rpcClients.getClient(it)) - ChainType.Cardano -> CardanoNodeStatusClient(it, rpcClients.getClient(it)) - } - } - ) + gateway: GemGateway, + ): NodeStatusService { + return NodeStatusService(gateway) } @Singleton diff --git a/app/src/main/kotlin/com/gemwallet/android/di/GatewayModule.kt b/app/src/main/kotlin/com/gemwallet/android/di/GatewayModule.kt new file mode 100644 index 000000000..2b0299cb8 --- /dev/null +++ b/app/src/main/kotlin/com/gemwallet/android/di/GatewayModule.kt @@ -0,0 +1,32 @@ +package com.gemwallet.android.di + +import android.content.Context +import com.gemwallet.android.data.repositoreis.config.SecurityGemPreferences +import com.gemwallet.android.data.repositoreis.config.SharedGemPreferences +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.AlienProvider +import uniffi.gemstone.GemGateway +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +object GatewayModule { + @Provides + @Singleton + fun provideGateway( + alienProvider: AlienProvider, + @ApplicationContext context: Context, + ): GemGateway { + return GemGateway( + alienProvider, + SharedGemPreferences( + context.getSharedPreferences("gateway_preferences", Context.MODE_PRIVATE) + ), + SecurityGemPreferences(context) + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestScene.kt b/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestScene.kt index f6b9169d8..e86f09d04 100644 --- a/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestScene.kt +++ b/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestScene.kt @@ -126,7 +126,7 @@ private fun Render( } item { PropertyItem("Method", request.method) } when (request.method) { - WalletConnectionMethods.solana_sign_transaction.string -> {} + WalletConnectionMethods.SolanaSignTransaction.string -> {} else -> item { Spacer(modifier = Modifier.size(24.dp)) Surface(shadowElevation = 16.dp, color = MaterialTheme.colorScheme.background) { diff --git a/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestViewModel.kt b/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestViewModel.kt index c9dda162f..d0fed1c9f 100644 --- a/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestViewModel.kt +++ b/app/src/main/kotlin/com/gemwallet/android/features/bridge/request/RequestViewModel.kt @@ -3,9 +3,9 @@ package com.gemwallet.android.features.bridge.request import androidx.core.net.toUri import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.gemwallet.android.blockchain.clients.SignClientProxy import com.gemwallet.android.blockchain.operators.LoadPrivateKeyOperator import com.gemwallet.android.blockchain.operators.PasswordStore +import com.gemwallet.android.blockchain.services.SignClientProxy import com.gemwallet.android.data.repositoreis.bridge.BridgesRepository import com.gemwallet.android.data.repositoreis.bridge.getNamespace import com.gemwallet.android.data.repositoreis.wallets.WalletsRepository @@ -70,8 +70,8 @@ class RequestViewModel @Inject constructor( } val params = when (request.request.method) { - WalletConnectionMethods.solana_sign_message.string, - WalletConnectionMethods.eth_sign.string -> { + WalletConnectionMethods.SolanaSignMessage.string, + WalletConnectionMethods.EthSign.string -> { val data = JSONArray(request.request.params).getString(1) String(data.decodeHex()) } @@ -80,7 +80,7 @@ class RequestViewModel @Inject constructor( val data = JSONArray(request.request.params).getString(1) data } - WalletConnectionMethods.personal_sign.string -> { + WalletConnectionMethods.PersonalSign.string -> { val data = JSONArray(request.request.params).getString(0) try { String(data.decodeHex()) @@ -88,9 +88,9 @@ class RequestViewModel @Inject constructor( data } } - WalletConnectionMethods.eth_send_transaction.string -> request.request.params - WalletConnectionMethods.solana_sign_and_send_transaction.string, - WalletConnectionMethods.solana_sign_transaction.string -> { + WalletConnectionMethods.EthSendTransaction.string -> request.request.params + WalletConnectionMethods.SolanaSignAndSendTransaction.string, + WalletConnectionMethods.SolanaSignTransaction.string -> { val params = JSONObject(request.request.params).getString("transaction") params } @@ -109,7 +109,7 @@ class RequestViewModel @Inject constructor( fun onSent(hash: String) { val sessionRequest = state.value.sessionRequest ?: return val data = when (state.value.sessionRequest?.request?.method) { - WalletConnectionMethods.solana_sign_transaction.string -> jsonEncoder.encodeToString(WCSolanaSignMessageResult(signature = hash)) + WalletConnectionMethods.SolanaSignTransaction.string -> jsonEncoder.encodeToString(WCSolanaSignMessageResult(signature = hash)) else -> hash } @@ -153,8 +153,8 @@ class RequestViewModel @Inject constructor( val sign = try { when (method) { - WalletConnectionMethods.eth_sign, - WalletConnectionMethods.personal_sign -> { + WalletConnectionMethods.EthSign, + WalletConnectionMethods.PersonalSign -> { val data = state.value.params.toByteArray() val decoder = SignMessageDecoder(SignMessage(SignDigestType.EIP191, data)) @@ -164,11 +164,11 @@ class RequestViewModel @Inject constructor( val param = decoder.hash() signClient.signMessage(chain, param, privateKey).toHexString() } - WalletConnectionMethods.eth_sign_typed_data, - WalletConnectionMethods.eth_sign_typed_data_v4 -> { + WalletConnectionMethods.EthSignTypedData, + WalletConnectionMethods.EthSignTypedDataV4 -> { signClient.signTypedMessage(chain, state.value.params.toByteArray(), privateKey).toHexString() } - WalletConnectionMethods.solana_sign_message -> { + WalletConnectionMethods.SolanaSignMessage -> { val param = state.value.params.toByteArray() signClient.signMessage(chain, param, privateKey).toHexString() } @@ -255,7 +255,7 @@ private data class RequestViewModelState( ), params = params, ) - WalletConnectionMethods.eth_send_transaction.string -> { + WalletConnectionMethods.EthSendTransaction.string -> { try { val jObj = JSONArray(params).getJSONObject(0) val to = jObj.getString("to") @@ -271,19 +271,35 @@ private data class RequestViewModelState( RequestSceneState.Error("Argument error: ${err.message}") } } - WalletConnectionMethods.solana_sign_transaction.string -> RequestSceneState.SignGeneric( + WalletConnectionMethods.SolanaSignTransaction.string -> RequestSceneState.SignGeneric( ConfirmParams.TransferParams.Generic( asset = chain.asset(), from = account, memo = params, + name = sessionRequest.peerMetaData?.name ?: "", + description = sessionRequest.peerMetaData?.description ?: "", + url = sessionRequest.peerMetaData?.url ?: "", + icon = sessionRequest.peerMetaData?.icons?.firstOrNull() ?: "", + redirectNative = sessionRequest.peerMetaData?.icons?.firstOrNull() ?: "", + redirectUniversal = sessionRequest.peerMetaData?.icons?.firstOrNull() ?: "", + gasLimit = "", + gasPrice = "", inputType = ConfirmParams.TransferParams.InputType.Signature ) ) - WalletConnectionMethods.solana_sign_and_send_transaction.string -> RequestSceneState.SignGeneric( + WalletConnectionMethods.SolanaSignAndSendTransaction.string -> RequestSceneState.SignGeneric( ConfirmParams.TransferParams.Generic( asset = chain.asset(), from = account, memo = params, + name = sessionRequest.peerMetaData?.name ?: "", + description = sessionRequest.peerMetaData?.description ?: "", + url = sessionRequest.peerMetaData?.url ?: "", + icon = sessionRequest.peerMetaData?.icons?.firstOrNull() ?: "", + redirectNative = sessionRequest.peerMetaData?.icons?.firstOrNull() ?: "", + redirectUniversal = sessionRequest.peerMetaData?.icons?.firstOrNull() ?: "", + gasLimit = "", + gasPrice = "", inputType = ConfirmParams.TransferParams.InputType.EncodeTransaction ) ) diff --git a/app/src/main/kotlin/com/gemwallet/android/features/confirm/viewmodels/ConfirmViewModel.kt b/app/src/main/kotlin/com/gemwallet/android/features/confirm/viewmodels/ConfirmViewModel.kt index 827996f86..ee0f58d17 100644 --- a/app/src/main/kotlin/com/gemwallet/android/features/confirm/viewmodels/ConfirmViewModel.kt +++ b/app/src/main/kotlin/com/gemwallet/android/features/confirm/viewmodels/ConfirmViewModel.kt @@ -3,10 +3,11 @@ package com.gemwallet.android.features.confirm.viewmodels import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.gemwallet.android.blockchain.clients.BroadcastClientProxy -import com.gemwallet.android.blockchain.clients.SignClientProxy import com.gemwallet.android.blockchain.operators.LoadPrivateKeyOperator import com.gemwallet.android.blockchain.operators.PasswordStore +import com.gemwallet.android.blockchain.services.BroadcastService +import com.gemwallet.android.blockchain.services.SignClientProxy +import com.gemwallet.android.blockchain.services.SignerPreloaderProxy import com.gemwallet.android.cases.transactions.CreateTransaction import com.gemwallet.android.data.repositoreis.assets.AssetsRepository import com.gemwallet.android.data.repositoreis.session.SessionRepository @@ -26,7 +27,6 @@ import com.gemwallet.android.model.Session import com.gemwallet.android.model.SignerParams import com.gemwallet.android.model.format import com.gemwallet.android.serializer.jsonEncoder -import com.gemwallet.android.services.SignerPreloaderProxy import com.gemwallet.android.ui.R import com.gemwallet.android.ui.components.CellEntity import com.gemwallet.android.ui.components.InfoSheetEntity @@ -74,7 +74,7 @@ class ConfirmViewModel @Inject constructor( private val passwordStore: PasswordStore, private val loadPrivateKeyOperator: LoadPrivateKeyOperator, private val signClient: SignClientProxy, - private val broadcastClientProxy: BroadcastClientProxy, + private val broadcastService: BroadcastService, private val createTransactionsCase: CreateTransaction, private val stakeRepository: StakeRepository, private val savedStateHandle: SavedStateHandle, @@ -95,7 +95,7 @@ class ConfirmViewModel @Inject constructor( private val assetsInfo = request.filterNotNull().mapNotNull { if (it is ConfirmParams.SwapParams) { - listOf(it.fromAsset.id, it.toAssetId) + listOf(it.fromAsset.id, it.toAsset.id) } else { listOf(it.assetId) } @@ -111,14 +111,7 @@ class ConfirmViewModel @Inject constructor( } val preload = try { - val result = signerPreload.preload(params = request) - when (request) { - is ConfirmParams.SwapParams -> if (result.scanTransaction?.isMalicious != false) { - throw Exception("Transaction payload error") - } - else -> {} - } - result + signerPreload.preload(params = request) } catch (err: Throwable) { state.update { ConfirmState.Error(ConfirmError.PreloadError(err.message ?: "Preload error")) } return@map null @@ -129,8 +122,8 @@ class ConfirmViewModel @Inject constructor( params.input is ConfirmParams.Stake.RewardsParams -> stakeRepository.getRewards(params.input.assetId, params.input.from.address) .map { BigInteger(it.base.rewards) } .fold(BigInteger.ZERO) { acc, value -> acc + value } - params.input.isMax() && params.input.assetId == params.chainData.fee(feePriority).feeAssetId -> - params.input.amount - params.chainData.fee(feePriority).amount + params.input.isMax() && params.input.assetId == params.fee(feePriority).feeAssetId -> + params.input.amount - params.fee(feePriority).amount else -> params.input.amount } state.update { ConfirmState.Ready } @@ -145,7 +138,7 @@ class ConfirmViewModel @Inject constructor( .stateIn(viewModelScope, SharingStarted.Eagerly, null) private val feeAssetInfo = preloadData.filterNotNull().flatMapLatest { signerParams -> - assetsRepository.getAssetInfo(signerParams.chainData.fee().feeAssetId) + assetsRepository.getAssetInfo(signerParams.fee().feeAssetId) } .stateIn(viewModelScope, SharingStarted.Eagerly, null) @@ -153,7 +146,7 @@ class ConfirmViewModel @Inject constructor( val fromAssetId = request?.assetId ?: return@combine null val assetInfo = assetsInfo?.getByAssetId(fromAssetId) ?: return@combine null val toAssetInfo = if (request is ConfirmParams.SwapParams) { - assetsInfo.getByAssetId(request.toAssetId) ?: return@combine null + assetsInfo.getByAssetId(request.toAsset.id) ?: return@combine null } else { null } @@ -192,8 +185,8 @@ class ConfirmViewModel @Inject constructor( .flowOn(Dispatchers.Default) .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) - val feeValue = combine(preloadData, feeAssetInfo, state, feePriority) { signerParams, feeAssetInfo, state, speed -> - val amount = signerParams?.chainData?.fee(speed)?.amount + val feeValue = combine(preloadData, feeAssetInfo, state, feePriority) { signerParams, feeAssetInfo, state, feePriority -> + val amount = signerParams?.fee(feePriority)?.amount if (amount == null || feeAssetInfo == null) { return@combine "" } @@ -203,8 +196,8 @@ class ConfirmViewModel @Inject constructor( .flowOn(Dispatchers.Default) .stateIn(viewModelScope, SharingStarted.Eagerly, "") - val feeUIModel = combine(preloadData, feeAssetInfo, state, feePriority) { signerParams, feeAssetInfo, state, speed -> - val amount = signerParams?.chainData?.fee(speed)?.amount + val feeUIModel = combine(preloadData, feeAssetInfo, state, feePriority) { signerParams, feeAssetInfo, state, priority -> + val amount = signerParams?.fee(priority)?.amount val result = if (amount == null || feeAssetInfo == null) { CellEntity( label = R.string.transfer_network_fee, @@ -255,7 +248,7 @@ class ConfirmViewModel @Inject constructor( .flowOn(Dispatchers.Default) .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) - val allFee = preloadData.filterNotNull().map { it.chainData.allFee() } + val allFee = preloadData.filterNotNull().map { it.allFee() } .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) fun init(params: ConfirmParams) { @@ -285,7 +278,7 @@ class ConfirmViewModel @Inject constructor( val account = assetInfo?.owner val feeAssetInfo = feeAssetInfo.value val session = sessionRepository.getSession() - val txSpeed = feePriority.value + val feePriority = this@ConfirmViewModel.feePriority.value try { if (assetInfo == null || account == null || session == null || feeAssetInfo == null) { @@ -293,12 +286,12 @@ class ConfirmViewModel @Inject constructor( } validateBalance( signerParams, - txSpeed, + feePriority, assetInfo, feeAssetInfo, getBalance(assetInfo, signerParams.input), ) - val signs = sign(signerParams, session, assetInfo, txSpeed) + val signs = sign(signerParams, session, assetInfo, feePriority) when (signerParams.input) { is ConfirmParams.TransferParams.Generic -> { when ((signerParams.input as ConfirmParams.TransferParams.Generic).inputType) { @@ -316,8 +309,8 @@ class ConfirmViewModel @Inject constructor( else -> {} } for (sign in signs) { - val txHash = broadcastClientProxy.send(account, sign, signerParams.input.getTxType()) - if (sign != signs.last()) { + val txHash = broadcastService.send(account, sign, signerParams.input.getTxType()) + if (!sign.contentEquals(signs.last())) { delay(500) } else { addTransaction(txHash) @@ -367,9 +360,9 @@ class ConfirmViewModel @Inject constructor( is ConfirmParams.Activate, is ConfirmParams.NftParams, is ConfirmParams.Stake.DelegateParams -> assetInfo.balance.balance.available.toBigInteger() - is ConfirmParams.Stake.RedelegateParams -> BigInteger(stakeRepository.getDelegation(params.srcValidatorId).firstOrNull()?.base?.balance ?: "0") - is ConfirmParams.Stake.UndelegateParams -> BigInteger(stakeRepository.getDelegation(params.validatorId, params.delegationId).firstOrNull()?.base?.balance ?: "0") - is ConfirmParams.Stake.WithdrawParams -> BigInteger(stakeRepository.getDelegation(params.validatorId, params.delegationId).firstOrNull()?.base?.balance ?: "0") + is ConfirmParams.Stake.RedelegateParams -> BigInteger(stakeRepository.getDelegation(params.delegation.validator.id).firstOrNull()?.base?.balance ?: "0") + is ConfirmParams.Stake.UndelegateParams -> BigInteger(stakeRepository.getDelegation(params.delegation.validator.id, params.delegation.base.delegationId).firstOrNull()?.base?.balance ?: "0") + is ConfirmParams.Stake.WithdrawParams -> BigInteger(stakeRepository.getDelegation(params.delegation.validator.id, params.delegation.base.delegationId).firstOrNull()?.base?.balance ?: "0") is ConfirmParams.Stake.RewardsParams -> stakeRepository.getRewards(assetInfo.asset.id, assetInfo.owner?.address ?: "") .fold(BigInteger.ZERO) { acc, delegation -> acc + BigInteger(delegation.base.balance) } } @@ -377,10 +370,10 @@ class ConfirmViewModel @Inject constructor( private suspend fun getValidator(params: ConfirmParams): DelegationValidator? { val validatorId = when (params) { - is ConfirmParams.Stake.DelegateParams -> params.validatorId - is ConfirmParams.Stake.RedelegateParams -> params.dstValidatorId - is ConfirmParams.Stake.UndelegateParams -> params.validatorId - is ConfirmParams.Stake.WithdrawParams -> params.validatorId + is ConfirmParams.Stake.DelegateParams -> params.validator.id + is ConfirmParams.Stake.RedelegateParams -> params.dstValidator.id + is ConfirmParams.Stake.UndelegateParams -> params.delegation.base.validatorId + is ConfirmParams.Stake.WithdrawParams -> params.delegation.base.validatorId is ConfirmParams.Activate, is ConfirmParams.Stake.RewardsParams, is ConfirmParams.SwapParams, @@ -456,7 +449,7 @@ class ConfirmViewModel @Inject constructor( jsonEncoder.encodeToString( TransactionSwapMetadata( fromAsset = input.fromAsset.id, - toAsset = input.toAssetId, + toAsset = input.toAsset.id, fromValue = input.fromAmount.toString(), toValue = input.toAmount.toString(), provider = input.protocolId, @@ -472,7 +465,7 @@ class ConfirmViewModel @Inject constructor( val assetInfo = assetsInfo.value?.getByAssetId(signerParams?.input?.assetId ?: return) ?: return val session = sessionRepository.getSession() val destinationAddress = signerParams.input.destination()?.address ?: "" - val txSpeed = feePriority.value + val priority = feePriority.value createTransactionsCase.createTransaction( hash = txHash, @@ -481,7 +474,7 @@ class ConfirmViewModel @Inject constructor( owner = assetInfo.owner!!, to = destinationAddress, state = TransactionState.Pending, - fee = signerParams.chainData.fee(txSpeed), + fee = signerParams.fee(priority), amount = signerParams.finalAmount, memo = signerParams.input.memo() ?: "", type = signerParams.input.getTxType(), @@ -491,7 +484,7 @@ class ConfirmViewModel @Inject constructor( } else { TransactionDirection.Outgoing }, - blockNumber = signerParams.chainData.blockNumber() + blockNumber = signerParams.data(feePriority.value).chainData.blockNumber() ) } @@ -504,7 +497,7 @@ class ConfirmViewModel @Inject constructor( assetBalance: BigInteger, ) { val amount = signerParams.finalAmount - val feeAmount = signerParams.chainData.fee(feePriority).amount + val feeAmount = signerParams.fee(feePriority).amount val totalAmount = when (signerParams.input.getTxType()) { TransactionType.Transfer, @@ -518,6 +511,10 @@ class ConfirmViewModel @Inject constructor( TransactionType.StakeWithdraw, TransactionType.TransferNFT -> amount TransactionType.SmartContractCall -> TODO() + TransactionType.PerpetualOpenPosition -> TODO() + TransactionType.PerpetualClosePosition -> TODO() + TransactionType.StakeFreeze -> TODO() + TransactionType.StakeUnfreeze -> TODO() } if (assetBalance < totalAmount) { @@ -525,7 +522,6 @@ class ConfirmViewModel @Inject constructor( throw ConfirmError.InsufficientBalance(label) } if (feeAssetInfo.balance.balance.available.toBigInteger() < feeAmount) { - val label = "${feeAssetInfo.id().chain.asset().name} (${feeAssetInfo.asset.symbol})" throw ConfirmError.InsufficientFee(chain = feeAssetInfo.asset.chain) } } diff --git a/app/src/main/kotlin/com/gemwallet/android/features/import_wallet/navigation/ImportWalletNavigation.kt b/app/src/main/kotlin/com/gemwallet/android/features/import_wallet/navigation/ImportWalletNavigation.kt index 9717b6b81..8f37f12ee 100644 --- a/app/src/main/kotlin/com/gemwallet/android/features/import_wallet/navigation/ImportWalletNavigation.kt +++ b/app/src/main/kotlin/com/gemwallet/android/features/import_wallet/navigation/ImportWalletNavigation.kt @@ -8,10 +8,10 @@ import androidx.navigation.compose.composable import androidx.navigation.navArgument import androidx.navigation.navOptions import androidx.navigation.navigation +import com.gemwallet.android.ext.toChain import com.gemwallet.android.features.import_wallet.views.ImportScreen import com.gemwallet.android.features.import_wallet.views.SelectImportTypeScreen import com.gemwallet.android.model.ImportType -import com.wallet.core.primitives.Chain import com.wallet.core.primitives.WalletType internal const val walletTypeArg = "wallet_type" @@ -56,7 +56,7 @@ fun NavGraphBuilder.importWalletScreen( val walletTypeString = entry.arguments?.getString(walletTypeArg) val chainString = entry.arguments?.getString(chainArg) val walletType = WalletType.entries.firstOrNull { it.string == walletTypeString } - val chain = Chain.entries.firstOrNull { it.string == chainString } + val chain = chainString?.toChain() if (walletType == null || (walletType != WalletType.multicoin && chain == null)) { onSelectType(null) } else { diff --git a/app/src/main/kotlin/com/gemwallet/android/services/SignerPreloaderProxy.kt b/app/src/main/kotlin/com/gemwallet/android/services/SignerPreloaderProxy.kt deleted file mode 100644 index cc0ec6d92..000000000 --- a/app/src/main/kotlin/com/gemwallet/android/services/SignerPreloaderProxy.kt +++ /dev/null @@ -1,156 +0,0 @@ -package com.gemwallet.android.services - -import com.gemwallet.android.blockchain.clients.ActivationTransactionPreloader -import com.gemwallet.android.blockchain.clients.ApprovalTransactionPreloader -import com.gemwallet.android.blockchain.clients.GenericTransferPreloader -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.NftTransactionPreloader -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.getClient -import com.gemwallet.android.cases.device.GetDeviceIdCase -import com.gemwallet.android.data.repositoreis.session.SessionRepository -import com.gemwallet.android.data.services.gemapi.GemApiClient -import com.gemwallet.android.ext.getAccount -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.ScanAddressTarget -import com.wallet.core.primitives.ScanTransaction -import com.wallet.core.primitives.ScanTransactionPayload -import com.wallet.core.primitives.Wallet -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class SignerPreloaderProxy( - private val gemApiClient: GemApiClient, - private val sessionRepository: SessionRepository, - private val getDeviceIdCase: GetDeviceIdCase, - private val nativeTransferClients: List, - private val tokenTransferClients: List, - private val stakeTransactionClients: List, - private val swapTransactionClients: List, - private val approvalTransactionClients: List, - private val activatePreloaderClients: List, - private val genericPreloaderClients: List, - private val nftPreloadClients: List, -) : GenericTransferPreloader, NativeTransferPreloader, TokenTransferPreloader, StakeTransactionPreloader, - SwapTransactionPreloader, ApprovalTransactionPreloader, ActivationTransactionPreloader, NftTransactionPreloader { - - suspend fun preload(params: ConfirmParams): SignerParams = withContext(Dispatchers.IO) { - - val isValidTransactionJob = async { - isValidTransaction( - getScanTransactionPayload( - params, - sessionRepository.getSession()?.wallet ?: throw IllegalStateException("Session isn't available"), - getDeviceIdCase.getDeviceId() - ) - ) - } - - val preloadJob = async { - when (params) { - is ConfirmParams.Stake -> preloadStake(params) - is ConfirmParams.SwapParams -> preloadSwap(params) - is ConfirmParams.TokenApprovalParams -> preloadApproval(params) - is ConfirmParams.TransferParams.Native -> preloadNativeTransfer(params) - is ConfirmParams.TransferParams.Token -> preloadTokenTransfer(params) - is ConfirmParams.Activate -> preloadActivate(params) - is ConfirmParams.TransferParams.Generic -> preloadGeneric(params) - is ConfirmParams.NftParams -> preloadNft(params) - } - } - - val isValidTransaction = isValidTransactionJob.await() - val preload = preloadJob.await() - preload.copy(scanTransaction = isValidTransaction) - } - - override fun supported(chain: Chain): Boolean { - return (nativeTransferClients - + tokenTransferClients - + stakeTransactionClients - + swapTransactionClients - + approvalTransactionClients).getClient(chain) != null - } - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - return nativeTransferClients.getClient(params.from.chain)?.preloadNativeTransfer(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams { - return tokenTransferClients.getClient(params.from.chain)?.preloadTokenTransfer(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadStake(params: ConfirmParams.Stake): SignerParams { - return stakeTransactionClients.getClient(params.from.chain)?.preloadStake(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - return swapTransactionClients.getClient(params.from.chain)?.preloadSwap(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadApproval(params: ConfirmParams.TokenApprovalParams): SignerParams { - return approvalTransactionClients.getClient(params.from.chain)?.preloadApproval(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadActivate(params: ConfirmParams.Activate): SignerParams { - return activatePreloaderClients.getClient(params.from.chain)?.preloadActivate(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadGeneric(params: ConfirmParams.TransferParams.Generic): SignerParams { - return genericPreloaderClients.getClient(params.from.chain)?.preloadGeneric(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - override suspend fun preloadNft(params: ConfirmParams.NftParams): SignerParams { - return nftPreloadClients.getClient(params.from.chain)?.preloadNft(params = params) - ?: throw IllegalArgumentException("Chain isn't support") - } - - private suspend fun isValidTransaction(payload: ScanTransactionPayload): ScanTransaction? { - return try { - gemApiClient.getScanTransaction(payload).data - } catch (_: Throwable) { - null - } - } - - private fun getScanTransactionPayload(params: ConfirmParams, wallet: Wallet, deviceId: String): ScanTransactionPayload { - val chain = params.assetId.chain - val origin = ScanAddressTarget( - chain = chain, - address = params.from.address, - ) - val target = when (params) { - is ConfirmParams.SwapParams -> ScanAddressTarget( - params.toAssetId.chain, - address = wallet.getAccount(params.toAssetId.chain)?.address ?: throw IllegalArgumentException("Account isn't available") - ) - is ConfirmParams.Stake -> ScanAddressTarget(chain, params.validatorId) - is ConfirmParams.TokenApprovalParams -> ScanAddressTarget(chain, params.contract) - is ConfirmParams.TransferParams.Native, - is ConfirmParams.TransferParams.Generic, - is ConfirmParams.TransferParams.Token -> ScanAddressTarget(chain, params.destination().address) - is ConfirmParams.Activate -> ScanAddressTarget(chain, params.from.address) - is ConfirmParams.NftParams -> ScanAddressTarget(chain, params.from.address) - } - - return ScanTransactionPayload( - deviceId = deviceId, - walletIndex = wallet.index.toUInt(), - origin = origin, - target = target, - type = params.getTxType(), - ) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/TestFormatter.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/TestFormatter.kt index 4facd9ddf..e735af02c 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/TestFormatter.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/TestFormatter.kt @@ -9,8 +9,8 @@ import java.util.Locale class TestFormatter { @Test fun testCompactFormat_Italy() { - assertEquals("5,00 Mio €", Currency.EUR.compactFormatter(5_000_000.0, Locale.ITALY)) - assertEquals("7,89 Mrd €", Currency.EUR.compactFormatter(7_890_000_000.0, Locale.ITALY)) + assertEquals("5,00 Mln €", Currency.EUR.compactFormatter(5_000_000.0, Locale.ITALY)) + assertEquals("7,89 Mld €", Currency.EUR.compactFormatter(7_890_000_000.0, Locale.ITALY)) assertEquals("1,20 Bln €", Currency.EUR.compactFormatter(1_200_000_000_000.0, Locale.ITALY)) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/algorand/TestAlgorandSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/algorand/TestAlgorandSigner.kt index 9dbb4ccf3..7e6c8cff4 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/algorand/TestAlgorandSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/algorand/TestAlgorandSigner.kt @@ -3,7 +3,6 @@ package com.gemwallet.android.blockchain.clients.algorand import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.DestinationAddress import com.gemwallet.android.model.Fee @@ -39,28 +38,27 @@ class TestAlgorandSigner { BigInteger.valueOf(10_000_000), DestinationAddress("GOZOAE6SH6XGGDRBQLZEDRITKMF5OLVJNACVRQBUEGFLBBR5I64A7QN63E"), ), - chainData = AlgorandSignPreloadClient.AlgorandChainData( - sequence = 46932581, + chainData = AlgorandChainData( + sequence = 46932581UL, block = "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", chainId = "mainnet-v1.0", - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Algorand), - amount = BigInteger.TEN - ) ), finalAmount = BigInteger.valueOf(10_000_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Algorand), + amount = BigInteger.TEN + ), privateKey.data(), ) } - assertEquals("0x82a3736967c44049c1faef9ca28e835bb980e84e2d6f6eaf866828abf8ce51f1820d04ea" + + assertEquals("82a3736967c44049c1faef9ca28e835bb980e84e2d6f6eaf866828abf8ce51f1820d04ea" + "87623069603104aaadcdea598dd6e77f8dbe40c7f9638485cfeda1609b810e23ce1604a374786e8" + "9a3616d74ce00989680a36665650aa26676ce02cc2265a367656eac6d61696e6e65742d76312e30" + "a26768c420c061c4d8fc1dbdded2d7604be4568e3f6d041987ac37bde4b620b5ab39248adfa26c7" + "6ce02cc264da3726376c42033b2e013d23fae630e2182f241c513530bd72ea9680558c034218ab0" + "863d47b8a3736e64c42033b2e013d23fae630e2182f241c513530bd72ea9680558c034218ab0863" + - "d47b8a474797065a3706179", sign.first().toHexString()) + "d47b8a474797065a3706179", String(sign.first())) } } \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBalance.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBalance.kt deleted file mode 100644 index 13c47e1b4..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBalance.kt +++ /dev/null @@ -1,161 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.ext.toIdentifier -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertNull -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class TestAptosBalance { - - companion object { - init { - includeLibs() - } - } - - @Test - fun testAptosBalance() { - val balancesService = TestAptosBalancesService(nativeBalance = "100000000") - val client = AptosBalanceClient( - chain = Chain.Aptos, - balanceService = balancesService - ) - - val result = runBlocking { - client.getNativeBalance(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f") - } - assertNotNull(result) - assertEquals("0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", balancesService.nativeRequest) - assertEquals("100000000", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(1.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(1.0, result.totalAmount) - assertEquals(AssetId(Chain.Aptos).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testAptosBalanceFail() { - val balanceService = TestAptosBalancesService() - val client = AptosBalanceClient( - chain = Chain.Aptos, - balanceService = balanceService - ) - - runBlocking { - val result = client.getNativeBalance(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f") - assertNull(result) - } - } - - @Test - fun testAptosBalanceBadValue() { - val balanceService = TestAptosBalancesService(nativeBalance = "0abcde") - val client = AptosBalanceClient( - chain = Chain.Aptos, - balanceService = balanceService - ) - - runBlocking { - val result = client.getNativeBalance(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f") - assertNull(result) - } - } - - @Test - fun testAptosBalanceEmpty() { - val balanceService = TestAptosBalancesService(nativeBalance = "0") - val client = AptosBalanceClient( - chain = Chain.Aptos, - balanceService = balanceService - ) - - val result = runBlocking { - client.getNativeBalance( - Chain.Aptos, - "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f" - ) - } - assertNotNull(result) - assertEquals("0", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(0.0, result.totalAmount) - assertEquals(AssetId(Chain.Aptos).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testAptos_tokens_balance() { - val balanceService = TestAptosBalancesService( - nativeBalance = "0", - ) - val assets = listOf( - Asset( - AssetId(Chain.Aptos, "0xe4ccb6d39136469f376242c31b34d10515c8eaaa38092f804db8e08a8f53c5b2::assets_v1::EchoCoin002"), - decimals = 6, - name = "Gui Inu", - symbol = "GUI", - type = AssetType.TOKEN - ), - Asset( - AssetId(Chain.Aptos, "0x159df6b7689437016108a019fd5bef736bac692b6d4a1f10c941f6fbb9a74ca6::oft::CakeOFT"), - decimals = 8, - name = "PancakeSwap Token", - symbol = "CAKE", - type = AssetType.TOKEN - ), - ) - val client = AptosBalanceClient( - chain = Chain.Aptos, - balanceService = balanceService - ) - - val result = runBlocking { - client.getTokenBalances( - Chain.Aptos, - "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", - assets, - ) - } - assertNotNull(result) - assertTrue(result.isNotEmpty()) - assertEquals(assets[0].id.toIdentifier(), result[0].asset.id.toIdentifier()) - assertEquals("30000000", result[0].balance.available) - assertEquals(30.0, result[0].balanceAmount.available) - assertEquals(assets[1].id.toIdentifier(), result[1].asset.id.toIdentifier()) - assertEquals("50000000", result[1].balance.available) - assertEquals(0.5, result[1].balanceAmount.available) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBalancesService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBalancesService.kt deleted file mode 100644 index cf5c78cb2..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBalancesService.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.aptos.services.AptosBalancesService -import com.wallet.core.blockchain.aptos.AptosResource -import com.wallet.core.blockchain.aptos.AptosResourceBalanceOptional -import com.wallet.core.blockchain.aptos.AptosResourceCoin -import okhttp3.ResponseBody -import okhttp3.ResponseBody.Companion.toResponseBody - -class TestAptosBalancesService( - val nativeBalance: String? = null, -) : AptosBalancesService { - - var nativeRequest: String? = null - var tokenRequest: String? = null - - override suspend fun balance(address: String, assetType: String): ResponseBody { - nativeRequest = address - nativeBalance ?: throw Exception() - return nativeBalance.toResponseBody() - } - override suspend fun resources(address: String): List> { - tokenRequest = address - return listOf( - AptosResource( - type = "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", - AptosResourceBalanceOptional( - AptosResourceCoin( - "10000000" - ) - ) - ), - AptosResource( - type = "0x1::coin::CoinStore<0xe4ccb6d39136469f376242c31b34d10515c8eaaa38092f804db8e08a8f53c5b2::assets_v1::EchoCoin002>", - AptosResourceBalanceOptional( - AptosResourceCoin( - "30000000" - ) - ) - ), - AptosResource( - type = "0x1::coin::CoinStore<0x159df6b7689437016108a019fd5bef736bac692b6d4a1f10c941f6fbb9a74ca6::oft::CakeOFT>", - AptosResourceBalanceOptional( - AptosResourceCoin( - "50000000" - ) - ) - ), - ) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSigner.kt index 14e9dce40..9ebc45f8a 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSigner.kt @@ -44,17 +44,16 @@ class TestAptosSigner { BigInteger.valueOf(10_000_000_000), DestinationAddress("0x82111f2975a0f6080d178236369b7479f6aed1203ef4a23f8205e4b91716b783"), ), - chainData = AptosSignerPreloader.AptosChainData( - 8L, - listOf(GasFee( - AssetId(Chain.Aptos), - priority = FeePriority.Normal, - maxGasPrice = BigInteger.valueOf(150L), - limit = BigInteger.valueOf(18L) - )) + chainData = AptosChainData( + 8UL, ), finalAmount = BigInteger.valueOf(10_000_000_000), - FeePriority.Normal, + GasFee( + AssetId(Chain.Aptos), + priority = FeePriority.Normal, + maxGasPrice = BigInteger.valueOf(150L), + limit = BigInteger.valueOf(18L) + ), privateKey.data(), ) } @@ -91,18 +90,17 @@ class TestAptosSigner { BigInteger.valueOf(10_000_000_000), DestinationAddress("0x82111f2975a0f6080d178236369b7479f6aed1203ef4a23f8205e4b91716b783"), ), - chainData = AptosSignerPreloader.AptosChainData( - 8L, - listOf(GasFee( - AssetId(Chain.Aptos), - priority = FeePriority.Normal, - maxGasPrice = BigInteger.valueOf(150L), - limit = BigInteger.valueOf(18L) - )) + chainData = AptosChainData( + 8UL, + ), + fee = GasFee( + AssetId(Chain.Aptos), + priority = FeePriority.Normal, + maxGasPrice = BigInteger.valueOf(150L), + limit = BigInteger.valueOf(18L) ), finalAmount = BigInteger.valueOf(10_000_000_000), - FeePriority.Normal, - privateKey.data(), + privateKey = privateKey.data(), ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinBalance.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinBalance.kt deleted file mode 100644 index f6437ae33..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinBalance.kt +++ /dev/null @@ -1,146 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinBalancesService -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.ext.toIdentifier -import com.wallet.core.blockchain.bitcoin.BitcoinAccount -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertNull -import kotlinx.coroutines.runBlocking -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class TestBitcoinBalance { - - companion object { - init { - includeLibs() - } - } - - @Test - fun testBitcoinBalance() { - val client = BitcoinBalanceClient( - chain = Chain.Bitcoin, - balanceService = object : BitcoinBalancesService { - override suspend fun balance(address: String): Result { - assertEquals("bc1qqypy0q4uwk8h845j8qc5r76zyk2fwdtvqy4s4x", address) - return Result.success(BitcoinAccount(balance = "100000000")) - } - } - ) - - val result = runBlocking { - client.getNativeBalance(Chain.Bitcoin, "bc1qqypy0q4uwk8h845j8qc5r76zyk2fwdtvqy4s4x") - } - assertNotNull(result) - assertEquals("100000000", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(1.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(1.0, result.totalAmount) - assertEquals(AssetId(Chain.Bitcoin).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testBitcoincacheBalance() { - var requestAddress: String? = null - val client = BitcoinBalanceClient( - chain = Chain.Bitcoin, - balanceService = object : BitcoinBalancesService { - override suspend fun balance(address: String): Result { - requestAddress = address - return Result.success(BitcoinAccount(balance = "100000000")) - } - } - ) - - runBlocking { - client.getNativeBalance(Chain.BitcoinCash, "qq29xrkkd68alnrca375qlfyhwdqdkevsvmgkq9cmw") - } - assertEquals("bitcoincash:qq29xrkkd68alnrca375qlfyhwdqdkevsvmgkq9cmw", requestAddress) - } - - @Test - fun testBitcoinBalanceFail() { - val client = BitcoinBalanceClient( - chain = Chain.Bitcoin, - balanceService = object : BitcoinBalancesService { - override suspend fun balance(address: String): Result { - return Result.failure(Exception()) - } - } - ) - - runBlocking { - val result = client.getNativeBalance(Chain.Bitcoin, "bc1qqypy0q4uwk8h845j8qc5r76zyk2fwdtvqy4s4x") - assertNull(result) - } - } - - @Test - fun testBitcoinBalanceBadValue() { - val client = BitcoinBalanceClient( - chain = Chain.Bitcoin, - balanceService = object : BitcoinBalancesService { - override suspend fun balance(address: String): Result { - return Result.success(BitcoinAccount("0abcdesdf")) - } - } - ) - - runBlocking { - val result = client.getNativeBalance(Chain.Bitcoin, "bc1qqypy0q4uwk8h845j8qc5r76zyk2fwdtvqy4s4x") - assertNull(result) - } - } - - @Test - fun testBitcoinBalanceEmpty() { - val client = BitcoinBalanceClient( - chain = Chain.Bitcoin, - balanceService = object : BitcoinBalancesService { - override suspend fun balance(address: String): Result { - return Result.success(BitcoinAccount("0")) - } - - } - ) - - runBlocking { - val result = client.getNativeBalance(Chain.Bitcoin, "bc1qqypy0q4uwk8h845j8qc5r76zyk2fwdtvqy4s4x") - assertNotNull(result) - assertEquals("0", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(0.0, result.totalAmount) - assertEquals(AssetId(Chain.Bitcoin).toIdentifier(), result.asset.id.toIdentifier()) - } - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSIgnerPreloader.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSIgnerPreloader.kt deleted file mode 100644 index 27f7ed693..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSIgnerPreloader.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinFeeService -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinUTXOService -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.toIdentifier -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.wallet.core.blockchain.bitcoin.BitcoinFeeResult -import com.wallet.core.blockchain.bitcoin.BitcoinUTXO -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import junit.framework.TestCase.assertEquals -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestBitcoinSignerPreloader { - - companion object { - init { - includeLibs() - } - } - - @Test - fun testBitcoinMinimumByteFee() { - assertEquals(BitcoinFeeCalculator.getMinimumByteFee(Chain.Bitcoin), BigInteger.ONE) - assertEquals(BitcoinFeeCalculator.getMinimumByteFee(Chain.Litecoin), BigInteger.valueOf(5)) - assertEquals(BitcoinFeeCalculator.getMinimumByteFee(Chain.Doge), BigInteger.valueOf(1000)) - } - - @Test - fun testBitcoinPreloader() { - var requestAddress = "" - val preloader = BitcoinSignerPreloader( - Chain.Bitcoin, - object : BitcoinUTXOService { - override suspend fun getUTXO(address: String): Result> { - requestAddress = address - - return Result.success( - listOf( - BitcoinUTXO( - txid = "9f47e5d5ae3dac0662766f95d0cdda9c242c08d6baac4ce5d82464cf948abd53", - vout = 1, - value = "86055170", - ) - ) - ) - } - - }, - object : BitcoinFeeService { - override suspend fun estimateFee(priority: String): Result { - val value = when (priority) { - "8" -> "0.17457567" - "4" -> "0.17457567" - "2" -> "0.60356369" - else -> return Result.failure(Exception("Incorrect priority")) - } - return Result.success(BitcoinFeeResult(value)) - } - } - ) - val result = runBlocking { - preloader.preloadNativeTransfer( - params = ConfirmParams.TransferParams.Native( - asset = Chain.Bitcoin.asset(), - from = Account( - Chain.Doge, - "DDyZeg24eU3csLa7LMWrZEoqnHXccz6c94", - "", - "dgub8rNuTi8ofZu1jVDKpBxW9VFo62kjjx3b6CcameEZnrNNHJ3sKCnWBxQSv6qAP6jrwZEpfT1ZdKsrcBFKGTMV8zgBtjZmvQt29VPnLzbHjjD" - ), - amount = BigInteger.valueOf(10_000_000_000), - destination = DestinationAddress("D8UBj4EfNfNWNCdnCSgpY48yZDqPdTZXWW"), - isMaxAmount = false - ) - ) - } - assertEquals("DDyZeg24eU3csLa7LMWrZEoqnHXccz6c94", requestAddress) - assertEquals(BigInteger.valueOf(10_000_000_000), result.input.amount) - assertEquals("DDyZeg24eU3csLa7LMWrZEoqnHXccz6c94", result.input.from.address) - assertEquals(AssetId(Chain.Bitcoin).toIdentifier(), result.input.assetId.toIdentifier()) - assertEquals(false, result.input.isMax()) - assertEquals("D8UBj4EfNfNWNCdnCSgpY48yZDqPdTZXWW", result.input.destination()?.address) - assertEquals(null, result.input.memo()) - assertEquals(BigInteger.valueOf(3351936), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(17458), result.chainData.gasFee().maxGasPrice) - assertEquals(BigInteger.valueOf(192), result.chainData.gasFee().limit) - assertEquals(AssetId(Chain.Doge).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals("9f47e5d5ae3dac0662766f95d0cdda9c242c08d6baac4ce5d82464cf948abd53", (result.chainData as BitcoinSignerPreloader.BitcoinChainData).utxo[0].txid) - assertEquals(1, (result.chainData as BitcoinSignerPreloader.BitcoinChainData).utxo[0].vout) - assertEquals("86055170", (result.chainData as BitcoinSignerPreloader.BitcoinChainData).utxo[0].value) - assertEquals(3, result.chainData.allFee().size) - assertEquals(BigInteger.valueOf(192), result.chainData.gasFee(FeePriority.Fast).limit) - assertEquals(BigInteger.valueOf(60357), result.chainData.gasFee(FeePriority.Fast).maxGasPrice) - assertEquals(BigInteger.valueOf(11588544), result.chainData.gasFee(FeePriority.Fast).amount) - assertEquals(BigInteger.valueOf(192), result.chainData.gasFee(FeePriority.Slow).limit) - assertEquals(BigInteger.valueOf(17458), result.chainData.gasFee(FeePriority.Slow).maxGasPrice) - assertEquals(BigInteger.valueOf(3351936), result.chainData.gasFee(FeePriority.Slow).amount) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSigner.kt index 0a55fb97b..1ace606fa 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinSigner.kt @@ -4,15 +4,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.DestinationAddress import com.gemwallet.android.model.GasFee -import com.wallet.core.blockchain.bitcoin.BitcoinUTXO import com.wallet.core.primitives.Account import com.wallet.core.primitives.AssetId import com.wallet.core.primitives.Chain import com.wallet.core.primitives.FeePriority +import com.wallet.core.primitives.UTXO import junit.framework.TestCase.assertEquals import kotlinx.coroutines.runBlocking import org.junit.Test @@ -25,7 +24,7 @@ import java.math.BigInteger class TestBitcoinSigner { companion object { - const val SIGN_RESULT = "0x010000000153bd8a94cf6424d8e54cacbad6082c249cdacdd0956f766206a" + + const val SIGN_RESULT = "010000000153bd8a94cf6424d8e54cacbad6082c249cdacdd0956f766206a" + "c3daed5e5479f010000006b483045022100ead2b7637532b167e66ddf76eafd032ada898c8719a" + "680de8183b71fb3086a3e022055a073be9148cb8b9dc71de04755dbf11f140fee167ed0d4b44d6" + "a54a829e75e012102fd6585adc0e86019abf00e83552d054cb5f4359ad4db8ca338099381f43e2" + @@ -49,29 +48,27 @@ class TestBitcoinSigner { BigInteger.valueOf(10_000_000_000), DestinationAddress("D8UBj4EfNfNWNCdnCSgpY48yZDqPdTZXWW"), ), - chainData = BitcoinSignerPreloader.BitcoinChainData( + chainData = BitcoinChainData( listOf( - BitcoinUTXO( - txid = "9f47e5d5ae3dac0662766f95d0cdda9c242c08d6baac4ce5d82464cf948abd53", + UTXO( + transaction_id = "9f47e5d5ae3dac0662766f95d0cdda9c242c08d6baac4ce5d82464cf948abd53", vout = 1, value = "86055170", + address = "" ) ), - listOf( - GasFee( - AssetId(Chain.Doge), - priority = FeePriority.Normal, - maxGasPrice = BigInteger.valueOf(150L), - limit = BigInteger.valueOf(18L) - ) - ) ), finalAmount = BigInteger.valueOf(10_000_000_000), - FeePriority.Normal, + fee = GasFee( + AssetId(Chain.Doge), + priority = FeePriority.Normal, + maxGasPrice = BigInteger.valueOf(150L), + limit = BigInteger.valueOf(18L) + ), privateKey.data() ) } - assertEquals(SIGN_RESULT, sign.first().toHexString()) + assertEquals(SIGN_RESULT, String(sign.first())) } } \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cardano/TestCardanoSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cardano/TestCardanoSigner.kt index 750f21742..8119071e8 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cardano/TestCardanoSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cardano/TestCardanoSigner.kt @@ -1,10 +1,8 @@ package com.gemwallet.android.blockchain.clients.cardano -import com.gemwallet.android.blockchain.clients.cardano.CardanoSignerPreloaderClient.CardanoChainData import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.DestinationAddress import com.gemwallet.android.model.Fee @@ -41,11 +39,6 @@ class TestCardanoSigner { DestinationAddress("addr1q9d2dxen8ywvs9yzxxn2w4mvffn797fquauvugt2ug7mfsuqj3lzdq9h0rsketzszrnfm930658swmpe7kpq53c2tmwql4rvtq"), ), chainData = CardanoChainData( - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Cardano), - amount = BigInteger.TEN - ), utxos = listOf( UTXO( address = "addr1q9d2dxen8ywvs9yzxxn2w4mvffn797fquauvugt2ug7mfsuqj3lzdq9h0rsketzszrnfm930658swmpe7kpq53c2tmwql4rvtq", @@ -56,18 +49,22 @@ class TestCardanoSigner { ) ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Cardano), + amount = BigInteger.TEN + ), privateKey.data(), ) } - assertEquals("0x83a40081825820412c5a964cf4515210bf4b82f45df6521c38e1e5381f27638fc509bef66" + + assertEquals("83a40081825820412c5a964cf4515210bf4b82f45df6521c38e1e5381f27638fc509bef66" + "79378010182825839015aa69b33391cc8148231a6a7576c4a67e2f920e778ce216ae23db4c380947" + "e2680b778e16cac5010e69d962fd50f076c39f5820a470a5edc192710825839015aa69b33391cc81" + "48231a6a7576c4a67e2f920e778ce216ae23db4c380947e2680b778e16cac5010e69d962fd50f076" + "c39f5820a470a5edc1a0076859c021a0002924b031a0b532b80a10081825820878150b7cb71f9406" + "e36dcdd250e22dc943ec4525233581536497acb4f13e670584004bf4935e4dcc7f54947c4eb0b9cd" + "d24880b168138af31b394ee0e7fe935900383822f432a1c2b533ea54f8ef12f1758b30a045f3918e" + - "f25a51dad762d071b0af6", sign.first().toHexString()) + "f25a51dad762d071b0af6", String(sign.first())) } } \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosBalances.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosBalances.kt deleted file mode 100644 index 8b93e4f3d..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosBalances.kt +++ /dev/null @@ -1,328 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosBalancesService -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosStakeService -import com.gemwallet.android.ext.toIdentifier -import com.wallet.core.blockchain.cosmos.CosmosBalance -import com.wallet.core.blockchain.cosmos.CosmosBalances -import com.wallet.core.blockchain.cosmos.CosmosDelegation -import com.wallet.core.blockchain.cosmos.CosmosDelegationData -import com.wallet.core.blockchain.cosmos.CosmosDelegations -import com.wallet.core.blockchain.cosmos.CosmosReward -import com.wallet.core.blockchain.cosmos.CosmosRewards -import com.wallet.core.blockchain.cosmos.CosmosUnboudingDelegationEntry -import com.wallet.core.blockchain.cosmos.CosmosUnboundingDelegation -import com.wallet.core.blockchain.cosmos.CosmosUnboundingDelegations -import com.wallet.core.blockchain.cosmos.CosmosValidators -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import kotlinx.coroutines.runBlocking -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class TestCosmosBalances { - - private class TestCosmosStakeService( - val delegations: List = emptyList(), - val unboundings: List = emptyList(), - val rewards: List = emptyList(), - ) : CosmosStakeService { - - var delegationsAddressRequest: String = "" - var unboundingAddressRequest: String = "" - var rewardsAddressRequest: String = "" - - override suspend fun validators(): Result { - return Result.success(CosmosValidators(emptyList())) - } - - override suspend fun delegations(address: String): Result { - delegationsAddressRequest = address - return Result.success(CosmosDelegations(delegations)) - } - - override suspend fun undelegations(address: String): Result { - unboundingAddressRequest = address - return Result.success(CosmosUnboundingDelegations(unboundings)) - } - - override suspend fun rewards(address: String): Result { - rewardsAddressRequest = address - return Result.success(CosmosRewards(rewards)) - } - - } - - @Test - fun testCosmosBalance() { - var ownerRequest: String = "" - val balanceService = object : CosmosBalancesService { - override suspend fun getBalance(owner: String): Result { - ownerRequest = owner - return Result.success( - CosmosBalances( - listOf( - CosmosBalance(denom = "uosmo", amount = "5272821") - ) - ) - ) - } - } - - val result = runBlocking { - CosmosBalanceClient( - Chain.Osmosis, - balancesService = balanceService, - stakeService = TestCosmosStakeService(), - ).getNativeBalance(Chain.Osmosis, "osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v") - } - assertEquals("osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v", ownerRequest) - assertNotNull(result) - assertEquals("5272821", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(5.272821, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(5.272821, result.totalAmount) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testCosmosBalanceStakeOnly() { - var ownerRequest: String = "" - val balanceService = object : CosmosBalancesService { - override suspend fun getBalance(owner: String): Result { - ownerRequest = owner - return Result.success(CosmosBalances(listOf())) - } - } - - val stakeService = TestCosmosStakeService( - delegations = listOf( - CosmosDelegation( - CosmosDelegationData("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm"), - CosmosBalance("uosmo", "1000000") - ), - CosmosDelegation( - CosmosDelegationData("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2"), - CosmosBalance("uosmo", "1000000") - ), - CosmosDelegation( - CosmosDelegationData("osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q"), - CosmosBalance("uosmo", "721000000") - ) - ) - ) - - val result = runBlocking { - CosmosBalanceClient( - Chain.Osmosis, - balancesService = balanceService, - stakeService = stakeService, - ).getNativeBalance(Chain.Osmosis, "osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v") - } - assertEquals("osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v", ownerRequest) - assertNotNull(result) - assertEquals("0", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("723000000", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(723.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(723.0, result.totalAmount) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testCosmosBalanceUnboundingOnly() { - var ownerRequest: String = "" - val balanceService = object : CosmosBalancesService { - override suspend fun getBalance(owner: String): Result { - ownerRequest = owner - return Result.success(CosmosBalances(listOf())) - } - } - val stakeService = TestCosmosStakeService( - unboundings = listOf( - CosmosUnboundingDelegation( - "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - entries = listOf( - CosmosUnboudingDelegationEntry( - creation_height = "25053096", - completion_time = "2024-12-18T02:11:27.650773866Z", - balance = "2000000", - ) - ) - ), - ) - ) - - val result = runBlocking { - CosmosBalanceClient( - Chain.Osmosis, - balancesService = balanceService, - stakeService = stakeService, - ).getNativeBalance(Chain.Osmosis, "osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v") - } - assertEquals("osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v", ownerRequest) - assertNotNull(result) - assertEquals("0", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("2000000", result.balance.pending) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(2.0, result.balanceAmount.pending) - assertEquals(2.0, result.totalAmount) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testCosmosBalanceRewardsOnly() { - var ownerRequest: String = "" - val balanceService = object : CosmosBalancesService { - override suspend fun getBalance(owner: String): Result { - ownerRequest = owner - return Result.success(CosmosBalances(listOf())) - } - } - val stakeService = TestCosmosStakeService( - rewards = listOf( - CosmosReward("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", listOf(CosmosBalance(denom = "uosmo", amount = "808.015913259210000000"))), - CosmosReward("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", listOf(CosmosBalance(denom = "uosmo", amount = "808.009961413523000000"))), - CosmosReward("osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q", listOf(CosmosBalance(denom = "uosmo", amount = "582579.692713670953000000"))), - ) - ) - - val result = runBlocking { - CosmosBalanceClient( - Chain.Osmosis, - balancesService = balanceService, - stakeService = stakeService, - ).getNativeBalance(Chain.Osmosis, "osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v") - } - assertEquals("osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v", ownerRequest) - assertNotNull(result) - assertEquals("0", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("584195", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.584195, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(0.584195, result.totalAmount) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.asset.id.toIdentifier()) - } - - @Test - fun testCosmosBalanceFull() { - var ownerRequest: String = "" - val balanceService = object : CosmosBalancesService { - override suspend fun getBalance(owner: String): Result { - ownerRequest = owner - return Result.success( - CosmosBalances( - listOf( - CosmosBalance(denom = "uosmo", amount = "5272821") - ) - ) - ) - } - } - - val stakeService = TestCosmosStakeService( - delegations = listOf( - CosmosDelegation( - CosmosDelegationData("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm"), - CosmosBalance("uosmo", "1000000") - ), - CosmosDelegation( - CosmosDelegationData("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2"), - CosmosBalance("uosmo", "1000000") - ), - CosmosDelegation( - CosmosDelegationData("osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q"), - CosmosBalance("uosmo", "721000000") - ) - ), - unboundings = listOf( - CosmosUnboundingDelegation( - "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - entries = listOf( - CosmosUnboudingDelegationEntry( - creation_height = "25053096", - completion_time = "2024-12-18T02:11:27.650773866Z", - balance = "2000000", - ) - ) - ), - ), - rewards = listOf( - CosmosReward("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", listOf(CosmosBalance(denom = "uosmo", amount = "808.015913259210000000"))), - CosmosReward("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", listOf(CosmosBalance(denom = "uosmo", amount = "808.009961413523000000"))), - CosmosReward("osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q", listOf(CosmosBalance(denom = "uosmo", amount = "582579.692713670953000000"))), - ) - ) - - val result = runBlocking { - CosmosBalanceClient( - Chain.Osmosis, - balancesService = balanceService, - stakeService = stakeService, - ).getNativeBalance(Chain.Osmosis, "osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v") - } - assertEquals("osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v", ownerRequest) - assertNotNull(result) - assertEquals("5272821", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("723000000", result.balance.staked) - assertEquals("584195", result.balance.rewards) - assertEquals("0", result.balance.reserved) - assertEquals("2000000", result.balance.pending) - assertEquals(5.272821, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(723.0, result.balanceAmount.staked) - assertEquals(0.584195, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(2.0, result.balanceAmount.pending) - assertEquals(730.857016, result.totalAmount) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.asset.id.toIdentifier()) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosSigner.kt index 1105ba766..14b8da275 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosSigner.kt @@ -39,21 +39,26 @@ class TestCosmosSigner { fun testSignNativeTransfer() { val transfer = ConfirmParams.Builder(Chain.Osmosis.asset(), osmoAccount, BigInteger.TEN) .transfer(DestinationAddress("osmo1rcjvzz8wzktqfz8qjf0l9q45kzxvd0z0n7l5cf")) as ConfirmParams.TransferParams.Native - val chainData = CosmosSignerPreloader.CosmosChainData( + val chainData = CosmosChainData( chainId = "osmosis-1", - accountNumber = 2913388L, - sequence = 10L, - fee = GasFee( - feeAssetId = AssetId(Chain.Osmosis), - maxGasPrice = BigInteger.valueOf(10000L), - limit = BigInteger.valueOf(200000L), - amount = BigInteger.valueOf(10000L), - priority = FeePriority.Normal, - ) + accountNumber = 2913388UL, + sequence = 10UL, ) val finalAmount = BigInteger.TEN val result = runBlocking { - signer.signNativeTransfer(transfer, chainData, finalAmount, FeePriority.Normal, privateKey) + signer.signNativeTransfer( + transfer, + chainData, + finalAmount, + fee = GasFee( + feeAssetId = AssetId(Chain.Osmosis), + maxGasPrice = BigInteger.valueOf(10000L), + limit = BigInteger.valueOf(200000L), + amount = BigInteger.valueOf(10000L), + priority = FeePriority.Normal, + ), + privateKey + ) }.first().toHexString() assertEquals( "0x7b226d6f6465223a2242524f4144434153545f4d4f44455f53594e43222c2274785f6279746573223" + @@ -77,21 +82,26 @@ class TestCosmosSigner { fun testSignStake() { val transfer = ConfirmParams.Builder(Chain.Osmosis.asset(), osmoAccount, BigInteger.TEN) .delegate("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm") - val chainData = CosmosSignerPreloader.CosmosChainData( + val chainData = CosmosChainData( chainId = "osmosis-1", - accountNumber = 2913388L, - sequence = 10L, - fee = GasFee( - feeAssetId = AssetId(Chain.Osmosis), - maxGasPrice = BigInteger.valueOf(10000L), - limit = BigInteger.valueOf(200000L), - amount = BigInteger.valueOf(10000L), - priority = FeePriority.Normal, - ) + accountNumber = 2913388UL, + sequence = 10UL, ) val finalAmount = BigInteger.TEN val result = runBlocking { - signer.signDelegate(transfer, chainData, finalAmount, FeePriority.Normal, privateKey) + signer.signDelegate( + transfer, + chainData, + finalAmount, + fee = GasFee( + feeAssetId = AssetId(Chain.Osmosis), + maxGasPrice = BigInteger.valueOf(10000L), + limit = BigInteger.valueOf(200000L), + amount = BigInteger.valueOf(10000L), + priority = FeePriority.Normal, + ), + privateKey + ) }.first().toHexString() assertEquals( "0x7b226d6f6465223a2242524f4144434153545f4d4f44455f53594e43222c2274785f6279746573223" + @@ -137,21 +147,26 @@ class TestCosmosSigner { ) ) ) - val chainData = CosmosSignerPreloader.CosmosChainData( + val chainData = CosmosChainData( chainId = "osmosis-1", - accountNumber = 2913388L, - sequence = 10L, - fee = GasFee( - feeAssetId = AssetId(Chain.Osmosis), - maxGasPrice = BigInteger.valueOf(10000L), - limit = BigInteger.valueOf(200000L), - amount = BigInteger.valueOf(10000L), - priority = FeePriority.Normal, - ) + accountNumber = 2913388UL, + sequence = 10UL, ) val finalAmount = BigInteger.TEN val result = runBlocking { - signer.signUndelegate(transfer, chainData, finalAmount, FeePriority.Normal, privateKey) + signer.signUndelegate( + transfer, + chainData, + finalAmount, + fee = GasFee( + feeAssetId = AssetId(Chain.Osmosis), + maxGasPrice = BigInteger.valueOf(10000L), + limit = BigInteger.valueOf(200000L), + amount = BigInteger.valueOf(10000L), + priority = FeePriority.Normal, + ), + privateKey + ) }.first().toHexString() assertEquals( "0x7b226d6f6465223a2242524f4144434153545f4d4f44455f53594e43222c2274785f6279746573223" + @@ -199,21 +214,26 @@ class TestCosmosSigner { ) ) ) - val chainData = CosmosSignerPreloader.CosmosChainData( + val chainData = CosmosChainData( chainId = "osmosis-1", - accountNumber = 2913388L, - sequence = 10L, - fee = GasFee( - feeAssetId = AssetId(Chain.Osmosis), - maxGasPrice = BigInteger.valueOf(10000L), - limit = BigInteger.valueOf(200000L), - amount = BigInteger.valueOf(10000L), - priority = FeePriority.Normal, - ) + accountNumber = 2913388UL, + sequence = 10UL, ) val finalAmount = BigInteger.TEN val result = runBlocking { - signer.signRedelegate(transfer, chainData, finalAmount, FeePriority.Normal, privateKey) + signer.signRedelegate( + transfer, + chainData, + finalAmount, + fee = GasFee( + feeAssetId = AssetId(Chain.Osmosis), + maxGasPrice = BigInteger.valueOf(10000L), + limit = BigInteger.valueOf(200000L), + amount = BigInteger.valueOf(10000L), + priority = FeePriority.Normal, + ), + privateKey + ) }.first().toHexString() assertEquals( "0x7b226d6f6465223a2242524f4144434153545f4d4f44455f53594e43222c2274785f6279746573223" + @@ -245,21 +265,26 @@ class TestCosmosSigner { "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", ), ) - val chainData = CosmosSignerPreloader.CosmosChainData( + val chainData = CosmosChainData( chainId = "osmosis-1", - accountNumber = 2913388L, - sequence = 10L, - fee = GasFee( - feeAssetId = AssetId(Chain.Osmosis), - maxGasPrice = BigInteger.valueOf(10000L), - limit = BigInteger.valueOf(200000L), - amount = BigInteger.valueOf(10000L), - priority = FeePriority.Normal, - ) + accountNumber = 2913388UL, + sequence = 10UL, ) val finalAmount = BigInteger.TEN val result = runBlocking { - signer.signRewards(transfer, chainData, finalAmount, FeePriority.Normal, privateKey) + signer.signRewards( + transfer, + chainData, + finalAmount, + fee = GasFee( + feeAssetId = AssetId(Chain.Osmosis), + maxGasPrice = BigInteger.valueOf(10000L), + limit = BigInteger.valueOf(200000L), + amount = BigInteger.valueOf(10000L), + priority = FeePriority.Normal, + ), + privateKey + ) }.first().toHexString() assertEquals( "0x7b226d6f6465223a2242524f4144434153545f4d4f44455f53594e43222c2274785f6279746573223" + diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEthSign.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEthSign.kt index 4a15d3ad9..ee7b98019 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEthSign.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEthSign.kt @@ -1,8 +1,8 @@ package com.gemwallet.android.blockchain.clients.evm import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.gemwallet.android.blockchain.clients.ethereum.EvmChainData import com.gemwallet.android.blockchain.clients.ethereum.EvmSignClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmSignerPreloader import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset @@ -46,22 +46,19 @@ class TestEthSign { destination = DestinationAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7"), from = Account(Chain.Ethereum, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", "") ), - chainData = EvmSignerPreloader.EvmChainData( + chainData = EvmChainData( chainId = 1, nonce = BigInteger.ONE, - fees = listOf( - GasFee( - maxGasPrice = BigInteger.TEN, - limit = BigInteger("21000"), - minerFee = BigInteger.TEN, - relay = BigInteger.TEN, - priority = FeePriority.Normal, - feeAssetId = Chain.Ethereum.asset().id, - ) - ) ), finalAmount = BigInteger.TEN.pow(Chain.Ethereum.asset().decimals), - feePriority = FeePriority.Normal, + fee = GasFee( + maxGasPrice = BigInteger.TEN, + limit = BigInteger("21000"), + minerFee = BigInteger.TEN, + relay = BigInteger.TEN, + priority = FeePriority.Normal, + feeAssetId = Chain.Ethereum.asset().id, + ), privateKey, ) } @@ -89,22 +86,19 @@ class TestEthSign { destination = DestinationAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7"), from = Account(Chain.Ethereum, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", "") ), - chainData = EvmSignerPreloader.EvmChainData( + chainData = EvmChainData( chainId = 1, nonce = BigInteger.ONE, - fees = listOf( - GasFee( - maxGasPrice = BigInteger.TEN, - limit = BigInteger("91000"), - minerFee = BigInteger.TEN, - relay = BigInteger.TEN, - priority = FeePriority.Normal, - feeAssetId = Chain.Ethereum.asset().id, - ) - ) ), finalAmount = BigInteger.TEN.pow(Chain.Ethereum.asset().decimals), - feePriority = FeePriority.Normal, + fee = GasFee( + maxGasPrice = BigInteger.TEN, + limit = BigInteger("91000"), + minerFee = BigInteger.TEN, + relay = BigInteger.TEN, + priority = FeePriority.Normal, + feeAssetId = Chain.Ethereum.asset().id, + ), privateKey, ) } @@ -140,22 +134,19 @@ class TestEthSign { value = "10", from = Account(Chain.Ethereum, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", "") ), - chainData = EvmSignerPreloader.EvmChainData( + chainData = EvmChainData( chainId = 1, nonce = BigInteger.ONE, - fees = listOf( - GasFee( - maxGasPrice = BigInteger.TEN, - limit = BigInteger("91000"), - minerFee = BigInteger.TEN, - relay = BigInteger.TEN, - priority = FeePriority.Normal, - feeAssetId = Chain.Ethereum.asset().id, - ) - ) ), finalAmount = BigInteger.TEN.pow(Chain.Ethereum.asset().decimals), - feePriority = FeePriority.Normal, + fee = GasFee( + maxGasPrice = BigInteger.TEN, + limit = BigInteger("91000"), + minerFee = BigInteger.TEN, + relay = BigInteger.TEN, + priority = FeePriority.Normal, + feeAssetId = Chain.Ethereum.asset().id, + ), privateKey, ) } @@ -177,22 +168,19 @@ class TestEthSign { from = Account(Chain.Ethereum, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), validatorId = "0x9941BCe2601fC93478DF9f5F6Cc83F4FFC1D71d8" ), - chainData = EvmSignerPreloader.EvmChainData( + chainData = EvmChainData( chainId = 1, nonce = BigInteger.ONE, - fees = listOf( - GasFee( - maxGasPrice = BigInteger.TEN, - limit = BigInteger("91000"), - minerFee = BigInteger.TEN, - relay = BigInteger.TEN, - priority = FeePriority.Normal, - feeAssetId = Chain.Ethereum.asset().id, - ) - ) ), finalAmount = BigInteger.TEN.pow(Chain.Ethereum.asset().decimals), - feePriority = FeePriority.Normal, + fee = GasFee( + maxGasPrice = BigInteger.TEN, + limit = BigInteger("91000"), + minerFee = BigInteger.TEN, + relay = BigInteger.TEN, + priority = FeePriority.Normal, + feeAssetId = Chain.Ethereum.asset().id, + ), privateKey, ) } @@ -220,22 +208,19 @@ class TestEthSign { share = "991645728829172501", balance = "1002901689671695193", ), - chainData = EvmSignerPreloader.EvmChainData( + chainData = EvmChainData( chainId = 1, nonce = BigInteger.ONE, - fees = listOf( - GasFee( - maxGasPrice = BigInteger.TEN, - limit = BigInteger("91000"), - minerFee = BigInteger.TEN, - relay = BigInteger.TEN, - priority = FeePriority.Normal, - feeAssetId = Chain.Ethereum.asset().id, - ) - ) ), finalAmount = BigInteger.TEN.pow(Chain.Ethereum.asset().decimals), - feePriority = FeePriority.Normal, + fee = GasFee( + maxGasPrice = BigInteger.TEN, + limit = BigInteger("91000"), + minerFee = BigInteger.TEN, + relay = BigInteger.TEN, + priority = FeePriority.Normal, + feeAssetId = Chain.Ethereum.asset().id, + ), privateKey, ) } @@ -268,22 +253,19 @@ class TestEthSign { provider = "Uniswap v3", contract = "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ), - chainData = EvmSignerPreloader.EvmChainData( + chainData = EvmChainData( chainId = 1, nonce = BigInteger.ONE, - fees = listOf( - GasFee( - maxGasPrice = BigInteger.TEN, - limit = BigInteger("91000"), - minerFee = BigInteger.TEN, - relay = BigInteger.TEN, - priority = FeePriority.Normal, - feeAssetId = Chain.SmartChain.asset().id, - ) - ) ), finalAmount = BigInteger.ZERO, - feePriority = FeePriority.Normal, + fee = GasFee( + maxGasPrice = BigInteger.TEN, + limit = BigInteger("91000"), + minerFee = BigInteger.TEN, + relay = BigInteger.TEN, + priority = FeePriority.Normal, + feeAssetId = Chain.SmartChain.asset().id, + ), privateKey, ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmBalance.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmBalance.kt deleted file mode 100644 index 7cd17da45..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmBalance.kt +++ /dev/null @@ -1,248 +0,0 @@ -package com.gemwallet.android.blockchain.clients.evm - -import com.gemwallet.android.blockchain.clients.ethereum.EvmBalanceClient -import com.gemwallet.android.blockchain.clients.ethereum.SmartchainStakeClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmBalancesService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.gemwallet.android.model.getTotalAmount -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertNull -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestEvmBalance { - - companion object { - init { - includeLibs() - } - } - - class CallService : EvmCallService { - override suspend fun callString(request: JSONRpcRequest>): Result> { - return Result.success(JSONRpcResponse("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000")) - } - - override suspend fun callNumber(request: JSONRpcRequest>): Result> { - return Result.success(JSONRpcResponse(null)) - } - - override suspend fun callBatch(request: List>>): Result>> { - return Result.success( - listOf( - JSONRpcResponse( - result = "0x00000000000000000000000000000000000000000000000000000000001fdcf1", - ) - ) - ) - } - - } - class BalanceService : EvmBalancesService { - var nativeBalanceParam: String = "" - - override suspend fun getBalance(request: JSONRpcRequest>): Result> { - nativeBalanceParam = request.params[0] - return Result.success(JSONRpcResponse(EvmRpcClient.EvmNumber(BigInteger.TEN.pow(16)))) - } - - } - - @Test - fun testNativeBalance() { - val balanceService = BalanceService() - val balanceClient = EvmBalanceClient(Chain.Ethereum, CallService(), balanceService, SmartchainStakeClient(Chain.Ethereum, CallService())) - - val result = runBlocking { - balanceClient.getNativeBalance(Chain.Ethereum, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - } - assertEquals("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", balanceService.nativeBalanceParam) - assertNotNull(result) - assertEquals("10000000000000000", result!!.balance.available) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.reserved) - assertEquals(BigInteger.valueOf(10_000_000_000_000_000), result.balance.getTotalAmount()) - assertEquals(0.01, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.reserved) - assertEquals(0.01, result.balanceAmount.getTotalAmount()) - } - - @Test - fun testNativeBalanceBadResponse() { - var nativeBalanceParam: String = "" - val balancesService = object : EvmBalancesService { - override suspend fun getBalance(request: JSONRpcRequest>): Result> { - nativeBalanceParam = request.params[0] - return Result.success(JSONRpcResponse(EvmRpcClient.EvmNumber(null))) - } - - } - val balanceClient = EvmBalanceClient(Chain.Ethereum, CallService(), balancesService, SmartchainStakeClient(Chain.Ethereum, CallService())) - - val result = runBlocking { - balanceClient.getNativeBalance(Chain.Ethereum, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - } - assertEquals("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", nativeBalanceParam) - assertNull(result) - } - - @Test - fun test_native_balance_on_SmartChain_without_delegations() { - val balanceService = BalanceService() - val balanceClient = EvmBalanceClient(Chain.SmartChain, CallService(), balanceService, SmartchainStakeClient(Chain.SmartChain, CallService())) - - val result = runBlocking { - balanceClient.getNativeBalance(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - } - assertNotNull(result) - assertEquals("10000000000000000", result!!.balance.available) - assertEquals("0", result.balance.rewards) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.reserved) - assertEquals(BigInteger.valueOf(10_000_000_000_000_000), result.balance.getTotalAmount()) - } - - @Test - fun test_native_balance_on_SmartChain_with_delegations() { - val balanceService = BalanceService() - val callService = object : EvmCallService { - override suspend fun callString(request: JSONRpcRequest>): Result> { - val data = when ((request.params[0] as Map<*, *>)["data"]) { - "0xced0e70e000000000000000000000000ee7e9ccfb529f2c1cc02c0aea8aced7ec7e98b5e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d" -> { - "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ee7e9ccfb529f2c1cc02c0aea8aced7ec7e98b5e0000000000000000000000009941bce2601fc93478df9f5f6cc83f4ffc1d71d80000000000000000000000000000000000000000000000000deacafbb23d1ee90000000000000000000000000000000000000000000000000dc3088951e56b15" - } - "0xd9d4c020000000000000000000000000ee7e9ccfb529f2c1cc02c0aea8aced7ec7e98b5e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d" -> { - "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - } - "0xc473318f" -> "0x000000000000000000000000000000000000000000000000000000000000002d" - else -> "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - } - return Result.success(JSONRpcResponse(data)) - } - - override suspend fun callNumber(request: JSONRpcRequest>): Result> { - TODO("Not yet implemented") - } - - override suspend fun callBatch(request: List>>): Result>> { - return Result.success( - listOf( - JSONRpcResponse( - result = "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ee7e9ccfb529f2c1cc02c0aea8aced7ec7e98b5e0000000000000000000000009941bce2601fc93478df9f5f6cc83f4ffc1d71d80000000000000000000000000000000000000000000000000deacafbb23d1ee90000000000000000000000000000000000000000000000000dc3088951e56b15", - ), - JSONRpcResponse( - result = "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", - ), - ) - ) - } - } - val balanceClient = EvmBalanceClient( - Chain.SmartChain, - callService, - balanceService, - SmartchainStakeClient(Chain.SmartChain, callService) - ) - - val result = runBlocking { - balanceClient.getDelegationBalances(Chain.SmartChain, "0xEe7E9CcFb529f2c1Cc02C0Aea8aCed7Ec7e98B5e") - } - assertNotNull(result) - assertEquals("0", result!!.balance.available) - assertEquals("0", result.balance.rewards) - assertEquals("1002837049419308777", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.reserved) - assertEquals(BigInteger.valueOf(1002837049419308777), result.balance.getTotalAmount()) - } - - @Test - fun testTokenBalance() { - val balanceService = BalanceService() - val callService = object : EvmCallService { - override suspend fun callString(request: JSONRpcRequest>): Result> { - TODO("Not yet implemented") - } - - override suspend fun callNumber(request: JSONRpcRequest>): Result> { - val result = when ((request.params[0] as Map<*, *>)["to"]) { - "0x76A797A59Ba2C17726896976B7B3747BfD1d220f" -> "0x00000000000000000000000000000000000000000000000000000002eedef652" - "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c" -> "0x000000000000000000000000000000000000000000000000006a94d74f430000" - else -> "0x" - } - return Result.success(JSONRpcResponse(EvmRpcClient.EvmNumber(BigInteger(result.removePrefix("0x"), 16)))) - } - - override suspend fun callBatch(request: List>>): Result>> { - return Result.success( - listOf( - JSONRpcResponse( - result = "0x00000000000000000000000000000000000000000000000000000002eedef652", - ), - JSONRpcResponse( - result = "0x000000000000000000000000000000000000000000000000006a94d74f430000", - ), - ) - ) - } - } - val balanceClient = EvmBalanceClient(Chain.SmartChain, callService, balanceService, SmartchainStakeClient(Chain.SmartChain, CallService())) - - val result = runBlocking { - balanceClient.getTokenBalances( - Chain.SmartChain, - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - listOf( - Asset( - AssetId(Chain.SmartChain, "0x76A797A59Ba2C17726896976B7B3747BfD1d220f"), - name = "ton", - symbol = "ton", - decimals = 9, - type = AssetType.ERC20 - ), - Asset( - AssetId(Chain.SmartChain, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), - name = "Wrapped BNB", - symbol = "WBNB", - decimals = 18, - type = AssetType.ERC20 - ), - ) - ) - } - assertNotNull(result) - assertEquals("12597524050", result[0].balance.available) - assertEquals("0", result[0].balance.rewards) - assertEquals("0", result[0].balance.staked) - assertEquals("0", result[0].balance.pending) - assertEquals("0", result[0].balance.frozen) - assertEquals("0", result[0].balance.locked) - assertEquals("0", result[0].balance.reserved) - assertEquals(BigInteger.valueOf(12597524050), result[0].balance.getTotalAmount()) - assertEquals("30000000000000000", result[1].balance.available) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmEncodeApprove.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmEncodeApprove.kt deleted file mode 100644 index e84ee2cab..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmEncodeApprove.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.gemwallet.android.blockchain.clients.evm - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.gemwallet.android.blockchain.clients.ethereum.encodeApprove -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.math.toHexString -import junit.framework.TestCase.assertEquals -import org.junit.Test -import org.junit.runner.RunWith -import wallet.core.jni.AnyAddress -import wallet.core.jni.CoinType - -@RunWith(AndroidJUnit4::class) -class TestEvmEncodeApprove { - - companion object { - init { - includeLibs() - } - } - - @Test - fun testEncodeApprove() { - assertEquals( - "0x095ea7b30000000000000000000000009b1db81180c31b1b428572be105e209b5a6222b77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - encodeApprove(AnyAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", CoinType.ETHEREUM).data()).toHexString() - ) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmExtentions.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmExtentions.kt deleted file mode 100644 index 993bbc677..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmExtentions.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.gemwallet.android.blockchain.clients.evm - -import com.gemwallet.android.blockchain.clients.ethereum.encodeTransactionData -import com.gemwallet.android.blockchain.clients.ethereum.getDestinationAddress -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.EVMChain -import junit.framework.TestCase.assertEquals -import org.junit.Test -import java.math.BigInteger - -class TestEvmExtentions { - companion object { - init { - includeLibs() - } - } - - @Test - fun testEncodeTransactionData() { - val result = EVMChain.encodeTransactionData( - AssetId(Chain.SmartChain, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), - null, - BigInteger.TEN, - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - ) - assertEquals( - "0xa9059cbb0000000000000000000000009b1db81180c31b1b428572be105e209b5a6222b7000000000" + - "000000000000000000000000000000000000000000000000000000a", - result.toHexString() - ) - } - - @Test - fun testEncodeTransactionData_with_memo() { - val result = EVMChain.encodeTransactionData( - AssetId(Chain.SmartChain, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), - "0x00000000000000000000000000000000000000000000000000000002eedef652", - BigInteger.TEN, - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - ) - assertEquals("0x00000000000000000000000000000000000000000000000000000002eedef652", result.toHexString()) - } - - @Test - fun testGetDestinationAddress_token() { - val result = EVMChain.getDestinationAddress( - AssetId(Chain.SmartChain, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7" - ) - assertEquals(result, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c") - } - - @Test - fun testGetDestinationAddress_native() { - val result = EVMChain.getDestinationAddress( - AssetId(Chain.SmartChain), - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7" - ) - assertEquals(result, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmTransactionStatusClient.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmTransactionStatusClient.kt deleted file mode 100644 index ef02627be..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestEvmTransactionStatusClient.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.gemwallet.android.blockchain.clients.evm - -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.ethereum.EvmTransactionStatusClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmTransactionsService -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.ethereum.EthereumTransactionReciept -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertNull -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestEvmTransactionStatusClient { - companion object { - init { - includeLibs() - } - } - - @Test - fun testEvm_transaction_tastus_confirm() { - val client = EvmTransactionStatusClient( - chain = Chain.SmartChain, - transactionsService = object : EvmTransactionsService { - override suspend fun transaction(request: JSONRpcRequest>): JSONRpcResponse { - return JSONRpcResponse( - EthereumTransactionReciept( - status = "0x1", - gasUsed = "10", - effectiveGasPrice = "2", - l1Fee = "1" - ) - ) - } - - } - ) - val resullt = runBlocking { - client.getStatus( - TransactionStateRequest( - Chain.SmartChain, - "0xe84b29d6f06aeb00ba071a409ff057649f19ebbc209114a6a8135a68af589e22", - "", - "0x502aECFE253E6AA0e8D2A06E12438FFeD0Fe16a0", - ) - ) - } - assertNotNull(resullt) - assertEquals(TransactionState.Confirmed, resullt.state) - assertEquals(BigInteger("21"), resullt.fee) - } - - @Test - fun testEvm_transaction_tastus_fail() { - val client = EvmTransactionStatusClient( - chain = Chain.SmartChain, - transactionsService = object : EvmTransactionsService { - override suspend fun transaction(request: JSONRpcRequest>): JSONRpcResponse { - return JSONRpcResponse( - EthereumTransactionReciept( - status = "0x0", - gasUsed = "10", - effectiveGasPrice = "2", - l1Fee = "1" - ) - ) - } - } - ) - val resullt = runBlocking { - client.getStatus( - TransactionStateRequest( - Chain.SmartChain, - "0xe84b29d6f06aeb00ba071a409ff057649f19ebbc209114a6a8135a68af589e22", - "", - "0x502aECFE253E6AA0e8D2A06E12438FFeD0Fe16a0", - ) - - ) - } - assertNotNull(resullt) - assertEquals(TransactionState.Reverted, resullt.state) - assertEquals(BigInteger("21"), resullt.fee) - } - - @Test - fun testEvm_transaction_tastus_pending() { - val client = EvmTransactionStatusClient( - chain = Chain.SmartChain, - transactionsService = object : EvmTransactionsService { - override suspend fun transaction(request: JSONRpcRequest>): JSONRpcResponse { - return JSONRpcResponse( - EthereumTransactionReciept( - status = "0x2", - gasUsed = "10", - effectiveGasPrice = "2", - l1Fee = "1" - ) - ) - } - - } - ) - val resullt = runBlocking { - client.getStatus( - TransactionStateRequest( - Chain.SmartChain, - "0xe84b29d6f06aeb00ba071a409ff057649f19ebbc209114a6a8135a68af589e22", - "", - "0x502aECFE253E6AA0e8D2A06E12438FFeD0Fe16a0", - ) - ) - } - assertNotNull(resullt) - assertEquals(TransactionState.Pending, resullt.state) - assertNull(resullt.fee) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestFeeCalculator.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestFeeCalculator.kt deleted file mode 100644 index 2023c7f38..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/evm/TestFeeCalculator.kt +++ /dev/null @@ -1,421 +0,0 @@ -package com.gemwallet.android.blockchain.clients.evm - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.gemwallet.android.blockchain.clients.ethereum.EvmFeeCalculator -import com.gemwallet.android.blockchain.clients.ethereum.StakeHub -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmFeeService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.wallet.core.blockchain.ethereum.EthereumFeeHistory -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import org.junit.Test -import org.junit.runner.RunWith -import uniffi.gemstone.Config -import wallet.core.jni.CoinType -import java.math.BigInteger - -@RunWith(AndroidJUnit4::class) -class TestFeeCalculator { - companion object { - init { - includeLibs() - } - } - - private class FeeService( - private val feeHistory: EthereumFeeHistory? = null, - private val gasLimit: BigInteger = BigInteger.valueOf(21_000), - ) : EvmFeeService { - - var feeHistoryRequest: List = emptyList() - var gasLimitRequest: List = emptyList() - - override suspend fun getFeeHistory(request: JSONRpcRequest>): Result> { - feeHistoryRequest = request.params - return Result.success(JSONRpcResponse(feeHistory ?: throw Exception("Fee history fail"))) - } - - override suspend fun getGasLimit(request: JSONRpcRequest>): Result> { - gasLimitRequest = request.params - return Result.success(JSONRpcResponse(EvmRpcClient.EvmNumber(gasLimit))) - } - - override suspend fun getNonce(request: JSONRpcRequest>): Result> { - return Result.success(JSONRpcResponse(EvmRpcClient.EvmNumber(BigInteger.ZERO))) - } - } - - private class CallService : EvmCallService { - override suspend fun callString(request: JSONRpcRequest>): Result> { - throw Exception("Call string fail") - } - - override suspend fun callNumber(request: JSONRpcRequest>): Result> { - return Result.success(JSONRpcResponse(EvmRpcClient.EvmNumber(BigInteger.ONE))) - } - - override suspend fun callBatch(request: List>>): Result>> { - TODO("Not yet implemented") - } - } - - @Test - fun testEvm_transfer_fee_calculation_network_fail_gas_limit() { - val feeService = object : EvmFeeService { - override suspend fun getFeeHistory(request: JSONRpcRequest>): Result> { - return Result.failure(Exception("Fee history fail")) - } - - override suspend fun getGasLimit(request: JSONRpcRequest>): Result> { - return Result.failure(Exception("Gas limit fail")) - } - - override suspend fun getNonce(request: JSONRpcRequest>): Result> { - return Result.failure(Exception("Nonce fail")) - } - } - val callService = object : EvmCallService { - override suspend fun callString(request: JSONRpcRequest>): Result> { - throw Exception("Call string fail") - } - - override suspend fun callNumber(request: JSONRpcRequest>): Result> { - throw Exception("Call number fail") - } - - override suspend fun callBatch(request: List>>): Result>> { - throw Exception("Call number fail") - } - } - try { - runBlocking { - EvmFeeCalculator( - feeService = feeService, - callService = callService, - coinType = CoinType.SMARTCHAIN, - ).calculate( - ConfirmParams.Builder( - Chain.SmartChain.asset(), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - DestinationAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - ), - AssetId(Chain.SmartChain), - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertTrue(false) - } catch (err: Throwable) { - assertTrue("Unable to calculate base fee" == err.message || "Fail calculate gas limit" == err.message) - } - } - - @Test - fun test_Evm_fee_transfer_calculation() { - val feeService = FeeService( - EthereumFeeHistory( - reward = listOf(listOf("0x3b9aca00")), - baseFeePerGas = listOf("0xa", "0xc"), - oldestBlock = "", - gasUsedRatio = emptyList() - ), - gasLimit = BigInteger.valueOf(25_000) - ) - val feeCalculator = EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ) - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - Chain.SmartChain.asset(), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - DestinationAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - ), - AssetId(Chain.SmartChain), - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertEquals(FeePriority.Normal, result[1].priority) - assertEquals(BigInteger("37500000450000"), result[1].amount) - assertEquals(BigInteger("1000000000"), result[1].minerFee) - assertEquals(BigInteger("1000000012"), result[1].maxGasPrice) - assertEquals(BigInteger("37500"), result[1].limit) - } - - @Test - fun test_Evm_fee_transfer_max_amount_calculation() { - val feeService = FeeService( - EthereumFeeHistory( - reward = listOf(listOf("0x3b9aca00")), - baseFeePerGas = listOf("0xa", "0xc"), - oldestBlock = "", - gasUsedRatio = emptyList() - ), - gasLimit = BigInteger.valueOf(25_000) - ) - val feeCalculator = EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ) - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - Chain.SmartChain.asset(), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - destination = DestinationAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7"), - isMax = true - ), - AssetId(Chain.SmartChain), - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertEquals(FeePriority.Normal, result[1].priority) - assertEquals(BigInteger("37500000450000"), result[1].amount) - assertEquals(BigInteger("1000000012"), result[1].minerFee) - assertEquals(BigInteger("1000000012"), result[1].maxGasPrice) - assertEquals(BigInteger("37500"), result[1].limit) - } - - - @Test - fun test_Evm_gas_limit_native_transfer_calculation() { - val feeService = FeeService( - EthereumFeeHistory( - reward = listOf(listOf("0x3b9aca00")), - baseFeePerGas = listOf("0x0", "0x0"), - oldestBlock = "", - gasUsedRatio = emptyList() - ), - gasLimit = BigInteger.valueOf(21_000) - ) - val feeCalculator = EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ) - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - Chain.SmartChain.asset(), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - DestinationAddress("0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A") - ), - AssetId(Chain.SmartChain), - "0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertEquals(FeePriority.Normal, result[1].priority) - assertEquals(BigInteger("21000000000000"), result[1].amount) - assertEquals(BigInteger.valueOf(21_000), result[1].limit) - assertEquals("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", (feeService.gasLimitRequest[0] as Map<*, *>)["from"]) - assertEquals("0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A", (feeService.gasLimitRequest[0] as Map<*, *>)["to"]) - assertEquals("0xa", (feeService.gasLimitRequest[0] as Map<*, *>)["value"]) - assertEquals("0x", (feeService.gasLimitRequest[0] as Map<*, *>)["data"]) - } - - @Test - fun test_Evm_Oracle() { - val feeService = FeeService( - EthereumFeeHistory( - reward = listOf(listOf("0x3b9aca00")), - baseFeePerGas = listOf("0x0", "0x0"), - oldestBlock = "", - gasUsedRatio = emptyList() - ), - gasLimit = BigInteger.valueOf(21_000) - ) - val feeCalculator = EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ) - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - Chain.OpBNB.asset(), - Account(Chain.OpBNB, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - DestinationAddress("0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A") - ), - AssetId(Chain.OpBNB), - "0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.OpBNB.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertEquals(FeePriority.Normal, result[1].priority) - assertEquals(BigInteger("21000000001"), result[1].amount) - assertEquals(BigInteger.valueOf(21_000), result[1].limit) - assertEquals("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", (feeService.gasLimitRequest[0] as Map<*, *>)["from"]) - assertEquals("0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A", (feeService.gasLimitRequest[0] as Map<*, *>)["to"]) - assertEquals("0xa", (feeService.gasLimitRequest[0] as Map<*, *>)["value"]) - assertEquals("0x", (feeService.gasLimitRequest[0] as Map<*, *>)["data"]) - } - - @Test - fun test_Evm_gas_limit_token_transfer_calculation() { - val feeService = FeeService( - EthereumFeeHistory( - reward = listOf(listOf("0x3b9aca00")), - baseFeePerGas = listOf("0x0", "0x0"), - oldestBlock = "", - gasUsedRatio = emptyList() - ), - gasLimit = BigInteger.valueOf(21_000) - ) - val feeCalculator = EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ) - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - Asset(AssetId(Chain.SmartChain, "0x2170Ed0880ac9A755fd29B2688956BD959F933F8"), name = "usdt", symbol = "usdt", decimals = 8, type = AssetType.TOKEN), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - DestinationAddress("0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A") - ), - AssetId(Chain.SmartChain, "0x2170Ed0880ac9A755fd29B2688956BD959F933F8"), - "0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertEquals(FeePriority.Normal, result[1].priority) - assertEquals(BigInteger("21000000000000"), result[1].amount) - assertEquals(BigInteger.valueOf(21_000), result[1].limit) - assertEquals("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", (feeService.gasLimitRequest[0] as Map<*, *>)["from"]) - assertEquals("0x2170ed0880ac9a755fd29b2688956bd959f933f8", (feeService.gasLimitRequest[0] as Map<*, *>)["to"]) - assertEquals("0x0", (feeService.gasLimitRequest[0] as Map<*, *>)["value"]) - assertEquals( - "0xa9059cbb000000000000000000000000a857a4e4b3f7c0eb7e132a7a4abca287225ddb2a000000000000000000000000000000000000000000000000000000000000000a", - (feeService.gasLimitRequest[0] as Map<*, *>)["data"] - ) - } - - @Test - fun test_Evm_gas_limit_delegate_calculation() { - val feeService = FeeService( - EthereumFeeHistory( - reward = listOf(listOf("0x3b9aca00")), - baseFeePerGas = listOf("0x0", "0x0"), - oldestBlock = "", - gasUsedRatio = emptyList() - ), - gasLimit = BigInteger.valueOf(21_000) - ) - val feeCalculator = EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ) - val params = ConfirmParams.Builder( - Chain.SmartChain.asset(), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).delegate("0xa857a4E4B3f7C0eb7e132A7A4abcA287225dDB2A") - val result = runBlocking { - feeCalculator.calculate( - params = params, - assetId = AssetId(Chain.SmartChain), - recipient = StakeHub.address, - outputAmount = BigInteger.TEN, - payload = "0xb", - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertEquals(FeePriority.Normal, result[1].priority) - assertEquals(BigInteger("21000000000000"), result[1].amount) - assertEquals(BigInteger.valueOf(21_000), result[1].limit) - assertEquals("0x9b1DB81180c31B1b428572Be105E209b5A6222b7", (feeService.gasLimitRequest[0] as Map<*, *>)["from"]) - assertEquals("0x0000000000000000000000000000000000002002", (feeService.gasLimitRequest[0] as Map<*, *>)["to"]) - assertEquals("0xa", (feeService.gasLimitRequest[0] as Map<*, *>)["value"]) - assertEquals("0xb", (feeService.gasLimitRequest[0] as Map<*, *>)["data"]) - } - - @Test - fun testEvm_transfer_fee_calculation_network_fail_fee_history() { - val feeService = FeeService( - gasLimit = BigInteger.valueOf(21_000) - ) - try { - runBlocking { - EvmFeeCalculator( - feeService = feeService, - callService = CallService(), - coinType = CoinType.SMARTCHAIN, - ).calculate( - ConfirmParams.Builder( - Chain.SmartChain.asset(), - Account(Chain.SmartChain, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - amount = BigInteger.TEN, - ).transfer( - DestinationAddress("0x9b1DB81180c31B1b428572Be105E209b5A6222b7") - ), - AssetId(Chain.SmartChain), - "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", - outputAmount = BigInteger.TEN, - null, - chainId = Config().getChainConfig(Chain.SmartChain.string).networkId.toInt(), - BigInteger.ZERO, - ) - } - assertTrue(false) - } catch (err: Throwable) { - assertEquals("Fee history fail", err.message) - } - } - - @Test - fun testEvm_transfer_fee_calculation_network_fail_L1Fee() { - - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/near/TestNearSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/near/TestNearSigner.kt index 1db53eab5..599bf0690 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/near/TestNearSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/near/TestNearSigner.kt @@ -1,6 +1,5 @@ package com.gemwallet.android.blockchain.clients.near -import com.gemwallet.android.blockchain.clients.near.NearSignerPreloader.NearChainData import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset @@ -43,15 +42,14 @@ class TestNearSigner { ), chainData = NearChainData( block = "2ADR7pgpkd2uFFkQcAyCxL5YB4d9SewALTLEuFbUUJLe", - sequence = 134180900000002, - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Near), - amount = BigInteger.TEN - ), + sequence = 134180900000002UL, ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Near), + amount = BigInteger.TEN + ), privateKey.data(), ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/polkadot/TestPolkadotSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/polkadot/TestPolkadotSigner.kt index 8f77cd239..5c9a4faad 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/polkadot/TestPolkadotSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/polkadot/TestPolkadotSigner.kt @@ -1,10 +1,8 @@ package com.gemwallet.android.blockchain.clients.polkadot -import com.gemwallet.android.blockchain.clients.polkadot.models.PolkadotSigningData import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.DestinationAddress import com.gemwallet.android.model.Fee @@ -41,33 +39,31 @@ class TestPolkadotSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = PolkadotSignerPreloaderClient.PolkadotChainData( - sequence = 0, - data = PolkadotSigningData( - genesisHash = "0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3", - blockHash = "0x6e3ffeaa3be9d19bd110e5b6e7cbbc92cceed0d2ec557276c296bf7970ace2e5", - blockNumber = BigInteger.valueOf(24666537), - specVersion = BigInteger.valueOf(1003004), - transactionVersion = BigInteger.valueOf(26), - period = 64, - ), - blockNumber = 24666537, - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Polkadot), - amount = BigInteger.TEN - ), + chainData = PolkadotChainData( + sequence = 0UL, + genesisHash = "0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3", + blockHash = "0x6e3ffeaa3be9d19bd110e5b6e7cbbc92cceed0d2ec557276c296bf7970ace2e5", + blockNumber = 24666537UL, + specVersion = 1003004UL, + transactionVersion = 26UL, + period = 64, ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Polkadot), + amount = BigInteger.TEN + ), privateKey.data(), ) } - assertEquals("0x35028400cd3cfbbaa8f217c2a29ceae4b4063b597b629861916bad98f9826e03d1ab120e0" + + assertEquals( + "0x35028400cd3cfbbaa8f217c2a29ceae4b4063b597b629861916bad98f9826e03d1ab120e0" + "0c094fad2608116257a997619a48d172340c69bca386c9f6b352903ee09a349b4ac90bff77872773" + "1dac78a56b6c5d901af843ca9c9a69b9e46cca042c4f70c099502000000050000cd3cfbbaa8f217c" + - "2a29ceae4b4063b597b629861916bad98f9826e03d1ab120e419c", sign.first().toHexString() + "2a29ceae4b4063b597b629861916bad98f9826e03d1ab120e419c", + String(sign.first()) ) } } \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaAccountsService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaAccountsService.kt deleted file mode 100644 index 5399f416e..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaAccountsService.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.solana.models.SolanaArrayData -import com.gemwallet.android.blockchain.clients.solana.models.SolanaInfo -import com.gemwallet.android.blockchain.clients.solana.models.SolanaParsedData -import com.gemwallet.android.blockchain.clients.solana.models.SolanaParsedSplTokenInfo -import com.gemwallet.android.blockchain.clients.solana.services.SolanaAccountsService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaAccount -import com.wallet.core.blockchain.solana.SolanaAccountParsed -import com.wallet.core.blockchain.solana.SolanaAccountParsedInfo -import com.wallet.core.blockchain.solana.SolanaTokenAccount -import com.wallet.core.blockchain.solana.SolanaTokenAmount -import com.wallet.core.blockchain.solana.SolanaTokenInfo -import com.wallet.core.blockchain.solana.SolanaValue - -internal class TestSolanaAccountsService( - private val tokenAddress: String? = null, - private val owner: String = "", -) : SolanaAccountsService { - var tokenAccountRequest: JSONRpcRequest>? = null - - override suspend fun getTokenAccountByOwner(request: JSONRpcRequest>): JSONRpcResponse>> { - tokenAccountRequest = request - return JSONRpcResponse( - SolanaValue( - listOf( - SolanaTokenAccount( - pubkey = tokenAddress ?: "", - account = SolanaAccount( - lamports = 100000, - space = 10, - owner = owner, - SolanaAccountParsed( - SolanaAccountParsedInfo( - SolanaTokenInfo( - SolanaTokenAmount(tokenAddress ?: (request.params[1] as Map<*, *>)["mint"].toString()) - ) - ) - ) - ) - ), - ) - ) - ) - } - - override suspend fun batchAccount(request: List>>): List>>> { - return request.mapIndexed { index, request -> - JSONRpcResponse( - SolanaValue( - listOf( - SolanaTokenAccount( - pubkey = tokenAddress ?: "", - account = SolanaAccount( - lamports = 100000, - space = 10, - owner = owner, - data = SolanaAccountParsed( - SolanaAccountParsedInfo( - SolanaTokenInfo( - SolanaTokenAmount(((index + 1) * 10000000).toString()) - ) - ) - ) - ) - ) - ) - ) - ) - } - } - - override suspend fun getAccountInfoSpl(request: JSONRpcRequest>): JSONRpcResponse>>> { - TODO("Not yet implemented") - } - - override suspend fun getAccountInfoMpl(request: JSONRpcRequest>): JSONRpcResponse>> { - TODO("Not yet implemented") - } - - override suspend fun getTokenInfo(request: JSONRpcRequest>): JSONRpcResponse> { - TODO("Not yet implemented") - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaBalances.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaBalances.kt deleted file mode 100644 index cec76dad0..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaBalances.kt +++ /dev/null @@ -1,299 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.solana.services.SolanaBalancesService -import com.gemwallet.android.blockchain.clients.solana.services.SolanaStakeService -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.gemwallet.android.model.getTotalAmount -import com.wallet.core.blockchain.solana.SolanaAccount -import com.wallet.core.blockchain.solana.SolanaAccountParsed -import com.wallet.core.blockchain.solana.SolanaAccountParsedInfo -import com.wallet.core.blockchain.solana.SolanaBalance -import com.wallet.core.blockchain.solana.SolanaBalanceValue -import com.wallet.core.blockchain.solana.SolanaEpoch -import com.wallet.core.blockchain.solana.SolanaRentExemptReserve -import com.wallet.core.blockchain.solana.SolanaStake -import com.wallet.core.blockchain.solana.SolanaStakeAccount -import com.wallet.core.blockchain.solana.SolanaStakeDelegation -import com.wallet.core.blockchain.solana.SolanaStakeInfo -import com.wallet.core.blockchain.solana.SolanaValidator -import com.wallet.core.blockchain.solana.SolanaValidators -import com.wallet.core.blockchain.solana.SolanaValue -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import kotlinx.coroutines.runBlocking -import org.junit.Test - -class TestSolanaBalances { - - companion object { - init { - includeLibs() - } - } - - private class TestBalancesService : SolanaBalancesService { - var nativeRequest: JSONRpcRequest>? = null - var tokenRequest: JSONRpcRequest>? = null - - override suspend fun getBalance(request: JSONRpcRequest>): Result> { - nativeRequest = request - return Result.success( - JSONRpcResponse( - SolanaBalance(1_000_000) - ) - ) - } - - override suspend fun getTokenBalance(request: JSONRpcRequest>): Result>> { - tokenRequest = request - return Result.success( - JSONRpcResponse( - SolanaValue( - SolanaBalanceValue( - when (request.params[0]) { - "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3" -> "5000000" - else -> "300000" - } - ) - ) - ) - ) - } - } - - private class TestStakeService( - private val delegationsResponse: JSONRpcResponse> = JSONRpcResponse(emptyList()) - ) : SolanaStakeService { - var validatorsRequest: JSONRpcRequest>? = null - var delegationsRequest: JSONRpcRequest>? = null - - override suspend fun validators(request: JSONRpcRequest>): Result> { - validatorsRequest = request - return Result.success( - JSONRpcResponse( - SolanaValidators( - listOf( - SolanaValidator("validatorPubKey", 10, true) - ) - ) - ) - ) - } - - override suspend fun delegations(request: JSONRpcRequest>): Result>> { - delegationsRequest = request - - return Result.success(delegationsResponse) - } - - override suspend fun epoch(request: JSONRpcRequest>): Result> { - return Result.success( - JSONRpcResponse( - SolanaEpoch( - epoch = 10, - slotsInEpoch = 1, - slotIndex = 1, - ) - ) - ) - } - } - - @Test - fun testSolana_balance_native() { - val accountsService = TestSolanaAccountsService() - val balancesService = TestBalancesService() - val stakeService = TestStakeService() - - val balanceClient = SolanaBalanceClient( - chain = Chain.Solana, - accountsService = accountsService, - balancesService = balancesService, - stakeService = stakeService, - ) - val result = runBlocking { - balanceClient.getNativeBalance(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh") - } - assertEquals("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", balancesService.nativeRequest!!.params[0]) - assertNotNull(result) - assertEquals(AssetId(Chain.Solana), result!!.asset.id) - assertEquals("1000000", result.balance.available) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.rewards) - } - - @Test - fun testSolana_balance_token() { - val accountsService = TestSolanaAccountsService() - val balancesService = TestBalancesService() - val stakeService = TestStakeService() - - val balanceClient = SolanaBalanceClient( - chain = Chain.Solana, - accountsService = accountsService, - balancesService = balancesService, - stakeService = stakeService, - ) - val result = runBlocking { - balanceClient.getTokenBalances( - Chain.Solana, - "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", - listOf( - Asset( - id = AssetId(Chain.Solana, "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"), - name = "Jupiter", - symbol = "JUP", - decimals = 6, - type = AssetType.TOKEN, - ), - Asset( - id = AssetId(Chain.Solana, "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3"), - name = "Pyth Network ", - symbol = "PYTH", - decimals = 6, - type = AssetType.TOKEN, - ), - ) - ) - } - assertNotNull(result) - assertEquals(2, result.size) - assertEquals(AssetId(Chain.Solana, "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"), result[0].asset.id) - assertEquals(AssetId(Chain.Solana, "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3"), result[1].asset.id) - assertEquals("10000000", result[0].balance.available) - assertEquals("20000000", result[1].balance.available) - } - - @Test - fun testSolana_balance_native_width_single_stake() { - val accountsService = TestSolanaAccountsService() - val balancesService = TestBalancesService() - val stakeService = TestStakeService( - delegationsResponse = JSONRpcResponse( - listOf( - SolanaStakeAccount( - pubkey = "", - account = SolanaAccount( - lamports = 1000000L, - space = 10, - owner = "", - data = SolanaAccountParsed( - SolanaAccountParsedInfo( - SolanaStakeInfo( - SolanaStake( - SolanaStakeDelegation("", "", "", ""), - ), - SolanaRentExemptReserve("") - ) - ) - ) - ) - ) - ) - - ) - ) - - val balanceClient = SolanaBalanceClient( - chain = Chain.Solana, - accountsService = accountsService, - balancesService = balancesService, - stakeService = stakeService, - ) - val result = runBlocking { - balanceClient.getDelegationBalances(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh") - } - assertNotNull(result) - assertEquals(AssetId(Chain.Solana), result!!.asset.id) - assertEquals("0", result.balance.available) - assertEquals("1000000", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.rewards) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.001, result.balanceAmount.staked) - assertEquals(0.001, result.balanceAmount.getTotalAmount()) - } - - @Test - fun testSolana_balance_native_width_multi_stake() { - val accountsService = TestSolanaAccountsService() - val balancesService = TestBalancesService() - val stakeService = TestStakeService( - delegationsResponse = JSONRpcResponse( - listOf( - SolanaStakeAccount( - pubkey = "", - account = SolanaAccount( - lamports = 1000000L, - space = 10, - owner = "", - data = SolanaAccountParsed( - SolanaAccountParsedInfo( - SolanaStakeInfo( - SolanaStake( - SolanaStakeDelegation("", "", "", ""), - ), - SolanaRentExemptReserve("") - ) - ) - ) - ) - ), - SolanaStakeAccount( - pubkey = "", - account = SolanaAccount( - lamports = 2000000, - space = 20, - owner = "", - data = SolanaAccountParsed( - SolanaAccountParsedInfo( - SolanaStakeInfo( - SolanaStake( - SolanaStakeDelegation("", "", "", ""), - ), - SolanaRentExemptReserve("") - ) - ) - ) - ) - ) - ) - ) - ) - - val balanceClient = SolanaBalanceClient( - chain = Chain.Solana, - accountsService = accountsService, - balancesService = balancesService, - stakeService = stakeService, - ) - val result = runBlocking { - balanceClient.getDelegationBalances(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh") - } - assertNotNull(result) - assertEquals(AssetId(Chain.Solana), result!!.asset.id) - assertEquals("0", result.balance.available) - assertEquals("3000000", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.rewards) - assertEquals(0.0, result.balanceAmount.available) - assertEquals(0.003, result.balanceAmount.staked) - assertEquals(0.003, result.balanceAmount.getTotalAmount()) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaFeeCalculation.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaFeeCalculation.kt deleted file mode 100644 index 0c2dc7496..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaFeeCalculation.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestSolanaFeeCalculation { - companion object { - init { - includeLibs() - } - } - - @Test - fun testSolana_calculate_native_fee() { - val feeCalculator = SolanaFeeCalculator(TestSolanaFeeService()) - - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - asset = Chain.Solana.asset(), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ).transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) - ) - } - assertEquals(BigInteger("100005000"), result[1].amount) - assertEquals(BigInteger("1000000000"), result[1].minerFee) - assertEquals(BigInteger("5000"), result[1].maxGasPrice) - assertEquals(BigInteger("100000"), result[1].limit) - assertEquals(BigInteger("30"), result[1].options["tokenAccountCreation"]) - } - - @Test - fun testSolana_calculate_native_fee_without_priority_fee() { - val feeCalculator = SolanaFeeCalculator(TestSolanaFeeService(fees = emptyList())) - - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - asset = Chain.Solana.asset(), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ).transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) - ) - } - assertEquals(BigInteger("10000"), result[1].amount) - assertEquals(BigInteger("50000"), result[1].minerFee) - assertEquals(BigInteger("5000"), result[1].maxGasPrice) - assertEquals(BigInteger("100000"), result[1].limit) - assertEquals(BigInteger("30"), result[1].options["tokenAccountCreation"]) - } - - @Test - fun testSolana_calculate_native_fee_without_create() { - val feeCalculator = SolanaFeeCalculator(TestSolanaFeeService(fees = emptyList())) - - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - asset = Chain.Solana.asset(), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ).transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) - ) - } - assertEquals(BigInteger("10000"), result[1].amount) - assertEquals(BigInteger("50000"), result[1].minerFee) - assertEquals(BigInteger("5000"), result[1].maxGasPrice) - assertEquals(BigInteger("100000"), result[1].limit) - assertEquals(BigInteger("0"), result[1].options["tokenAccountCreation"]) - } - - @Test - fun testSolana_calculate_token_fee_without_create() { - val feeCalculator = SolanaFeeCalculator(TestSolanaFeeService(listOf(100, 200))) - - val result = runBlocking { - feeCalculator.calculate( - ConfirmParams.Builder( - asset = Asset(AssetId(Chain.Solana, "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), name = "usdt", symbol = "usdt", decimals = 8, type = AssetType.TOKEN), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ).transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) - ) - } - assertEquals(BigInteger("15000"), result[1].amount) - assertEquals(BigInteger("100000"), result[1].minerFee) - assertEquals(BigInteger("5000"), result[1].maxGasPrice) - assertEquals(BigInteger("100000"), result[1].limit) - assertEquals(BigInteger("30"), result[1].options["tokenAccountCreation"]) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaFeeService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaFeeService.kt deleted file mode 100644 index 5ce88aea8..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaFeeService.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.solana.services.SolanaFeeService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaPrioritizationFee - -internal class TestSolanaFeeService( - private val fees: List = listOf(100000000, 2000000000), -) : SolanaFeeService { - - override suspend fun getPriorityFees(request: JSONRpcRequest>): Result>> { - return Result.success(JSONRpcResponse(fees.map { SolanaPrioritizationFee(it) })) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSignPreloader.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSignPreloader.kt deleted file mode 100644 index 225f9dfcf..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSignPreloader.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.solana.services.SolanaNetworkInfoService -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.wallet.core.blockchain.solana.SolanaBlockhash -import com.wallet.core.blockchain.solana.SolanaBlockhashResult -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.SolanaTokenProgramId -import junit.framework.TestCase.assertEquals -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestSolanaSignPreloader { - - companion object { - init { - includeLibs() - } - } - - private class TestSolanaNetworkInfoService( - val blockhash: String = "", - ) : SolanaNetworkInfoService { - - override suspend fun getBlockhash(request: JSONRpcRequest>): Result> { - return Result.success(JSONRpcResponse(SolanaBlockhashResult(SolanaBlockhash(blockhash)))) - } - - } - - @Test - fun testSolana_netive_transfer_preload() { - val preloader = SolanaSignerPreloader( - chain = Chain.Solana, - feeService = TestSolanaFeeService(), - networkInfoService = TestSolanaNetworkInfoService(blockhash = "123"), - accountsService = TestSolanaAccountsService(), - ) - - val result = runBlocking { - preloader.preloadNativeTransfer( - ConfirmParams.Builder( - asset = Chain.Solana.asset(), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ) - .transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) as ConfirmParams.TransferParams.Native - ) - } - assertEquals(BigInteger("100005000"), result.chainData.gasFee().amount) - assertEquals("123", (result.chainData as SolanaSignerPreloader.SolanaChainData).blockhash) - assertEquals(SolanaTokenProgramId.Token, (result.chainData as SolanaSignerPreloader.SolanaChainData).tokenProgram) - assertEquals(null, (result.chainData as SolanaSignerPreloader.SolanaChainData).recipientTokenAddress) - assertEquals("", (result.chainData as SolanaSignerPreloader.SolanaChainData).senderTokenAddress) - } - - @Test - fun testSolana_transfer_token_preload() { - val preloader = SolanaSignerPreloader( - chain = Chain.Solana, - feeService = TestSolanaFeeService(), - networkInfoService = TestSolanaNetworkInfoService(blockhash = "123"), - accountsService = TestSolanaAccountsService( - "DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", - "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - ), - ) - - val result = runBlocking { - preloader.preloadTokenTransfer( - ConfirmParams.Builder( - asset = Asset(AssetId(Chain.Solana, "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), name = "usdt", symbol = "usdt", decimals = 8, type = AssetType.TOKEN), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ) - .transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) as ConfirmParams.TransferParams.Token - ) - } - assertEquals(BigInteger("100005000"), result.chainData.gasFee().amount) - assertEquals("123", (result.chainData as SolanaSignerPreloader.SolanaChainData).blockhash) - assertEquals(SolanaTokenProgramId.Token, (result.chainData as SolanaSignerPreloader.SolanaChainData).tokenProgram) - assertEquals("DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", (result.chainData as SolanaSignerPreloader.SolanaChainData).recipientTokenAddress) - assertEquals("DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", (result.chainData as SolanaSignerPreloader.SolanaChainData).senderTokenAddress) - } - - @Test - fun testSolana_transfer_token2022_preload() { - val preloader = SolanaSignerPreloader( - chain = Chain.Solana, - feeService = TestSolanaFeeService(), - networkInfoService = TestSolanaNetworkInfoService(blockhash = "123"), - accountsService = TestSolanaAccountsService( - "87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", - "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" - ), - ) - - val result = runBlocking { - preloader.preloadTokenTransfer( - ConfirmParams.Builder( - asset = Asset(AssetId(Chain.Solana, "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo"), name = "smt", symbol = "", decimals = 8, type = AssetType.TOKEN), - from = Account(Chain.Solana, "AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh", ""), - amount = BigInteger.valueOf(10_000_000) - ) - .transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) as ConfirmParams.TransferParams.Token - ) - } - assertEquals(BigInteger("100005000"), result.chainData.gasFee().amount) - assertEquals("123", (result.chainData as SolanaSignerPreloader.SolanaChainData).blockhash) - assertEquals(SolanaTokenProgramId.Token2022, (result.chainData as SolanaSignerPreloader.SolanaChainData).tokenProgram) - assertEquals("87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", (result.chainData as SolanaSignerPreloader.SolanaChainData).recipientTokenAddress) - assertEquals("87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", (result.chainData as SolanaSignerPreloader.SolanaChainData).senderTokenAddress) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSigner.kt index 144dae779..643bd066d 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/solana/TestSolanaSigner.kt @@ -46,14 +46,22 @@ class TestSolanaSigner { } ) val params = ConfirmParams.Builder( - asset = Chain.Solana.asset(), - from = Account(Chain.Solana, "4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S", ""), - amount = BigInteger.valueOf(10_000_000) - ) + asset = Chain.Solana.asset(), + from = Account(Chain.Solana, "4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S", ""), + amount = BigInteger.valueOf(10_000_000) + ) .transfer(destination = DestinationAddress("4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S")) as ConfirmParams.TransferParams.Native - val chainData = SolanaSignerPreloader.SolanaChainData( + val chainData = SolanaChainData( blockhash = "kiEPF6aKvEsj5nbi4FBvgRRm9ha36Y3cgDU9qnUKt32", - fees = listOf( + recipientTokenAddress = null, + senderTokenAddress = "", + tokenProgram = SolanaTokenProgramId.Token + ) + val result = runBlocking { + signer.signNativeTransfer( + params, + chainData, + BigInteger.ZERO, GasFee( amount = BigInteger("105005000"), minerFee = BigInteger("1050000000"), @@ -62,22 +70,21 @@ class TestSolanaSigner { feeAssetId = AssetId(Chain.Solana), priority = FeePriority.Normal, ), - ), - recipientTokenAddress = null, - senderTokenAddress = "", - tokenProgram = SolanaTokenProgramId.Token + privateKey + ) + } + assertEquals( + "0x4159436b734f696556323339774436566c6841614a41464844544a647a632f61577a3331" + + "6f693676686e783978676d4c544a5372643165504634454e73734a704867667575424e6e55556b3" + + "159304a52784e504a59513442414149455365626b44466a2b415242396b4b486b394f4167745057" + + "456e614370426a475a3869707a61372f4e43577330767554324f647746546758414767305a61753" + + "17474703157354f7153437a77434c53384e5738357a71514d47526d2f6c495263792f2b7974756e" + + "4c446d2b65386a4f573778666353617978446d7a704141414141414141414141414141414141414" + + "141414141414141414141414141414141414141414141414141414141414c4d706730536d427863" + + "684e486e756872566468464259677863634c722b5370616932436959444a4b51514d4341416b446" + + "74c71565067414141414143414155436f49594241414d434141454d416741414141414141414141" + + "41414141", result.first().toHexString() ) - val result = runBlocking { signer.signNativeTransfer(params, chainData, BigInteger.ZERO, FeePriority.Normal, privateKey) } - assertEquals("0x4159436b734f696556323339774436566c6841614a41464844544a647a632f61577a3331" + - "6f693676686e783978676d4c544a5372643165504634454e73734a704867667575424e6e55556b3" + - "159304a52784e504a59513442414149455365626b44466a2b415242396b4b486b394f4167745057" + - "456e614370426a475a3869707a61372f4e43577330767554324f647746546758414767305a61753" + - "17474703157354f7153437a77434c53384e5738357a71514d47526d2f6c495263792f2b7974756e" + - "4c446d2b65386a4f573778666353617978446d7a704141414141414141414141414141414141414" + - "141414141414141414141414141414141414141414141414141414141414c4d706730536d427863" + - "684e486e756872566468464259677863634c722b5370616932436959444a4b51514d4341416b446" + - "74c71565067414141414143414155436f49594241414d434141454d416741414141414141414141" + - "41414141", result.first().toHexString()) } @Test @@ -95,14 +102,28 @@ class TestSolanaSigner { } ) val params = ConfirmParams.Builder( - asset = Asset(AssetId(Chain.Solana, "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), "", "", 8, AssetType.TOKEN), - from = Account(Chain.Solana, "4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S", ""), - amount = BigInteger.valueOf(10_000_000) - ) + asset = Asset( + AssetId(Chain.Solana, "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), + "", + "", + 8, + AssetType.TOKEN + ), + from = Account(Chain.Solana, "4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S", ""), + amount = BigInteger.valueOf(10_000_000) + ) .transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) as ConfirmParams.TransferParams.Token - val chainData = SolanaSignerPreloader.SolanaChainData( + val chainData = SolanaChainData( blockhash = "kiEPF6aKvEsj5nbi4FBvgRRm9ha36Y3cgDU9qnUKt32", - fees = listOf( + recipientTokenAddress = "DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", + senderTokenAddress = "DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", + tokenProgram = SolanaTokenProgramId.Token + ) + val result = runBlocking { + signer.signTokenTransfer( + params, + chainData, + BigInteger.ZERO, GasFee( amount = BigInteger("105005000"), minerFee = BigInteger("1050000000"), @@ -110,24 +131,23 @@ class TestSolanaSigner { limit = BigInteger("100000"), feeAssetId = AssetId(Chain.Solana), priority = FeePriority.Normal, - ) - ), - recipientTokenAddress = "DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", - senderTokenAddress = "DVWPV7brSbPDkA7a3qdn6UJsVc3J3DyhQhjNaZeZqwzo", - tokenProgram = SolanaTokenProgramId.Token + ), + privateKey + ) + } + assertEquals( + "0x416238786c7268464374766e72677357477874416f6b6852423654737057545862643066" + + "6e31557835466c736b734b317838714d6668326e313662454d384d6b6a4a4d467450664b7046684" + + "25a376576716557713051514241414d465365626b44466a2b415242396b4b486b394f4167745057" + + "456e614370426a475a3869707a61372f4e435775356d6277492b744e3454586473757149654b725" + + "254647a734b644444707a385843635179334a766a50304d3442446d43763762496e4637316a4753" + + "395546466f2f6c6c6f7a75344c5378774b657373346549494a6b41775a47622b5568467a4c2f374" + + "b323663734f623537794d3562764639784a724c454f624f6b41414141414733666268313257686b" + + "396e4c3455624f36336d73484c5346375639624e3545366a50574666763841715173796d44524b5" + + "948467945306565364774563245554669444678777576354b6c714c594b4a674d6b704241774d41" + + "43514f417570552b4141414141414d4142514b67686745414241514241674541436777414141414" + + "1414141414141593d", result.first().toHexString() ) - val result = runBlocking { signer.signTokenTransfer(params, chainData, BigInteger.ZERO, FeePriority.Normal, privateKey) } - assertEquals("0x416238786c7268464374766e72677357477874416f6b6852423654737057545862643066" + - "6e31557835466c736b734b317838714d6668326e313662454d384d6b6a4a4d467450664b7046684" + - "25a376576716557713051514241414d465365626b44466a2b415242396b4b486b394f4167745057" + - "456e614370426a475a3869707a61372f4e435775356d6277492b744e3454586473757149654b725" + - "254647a734b644444707a385843635179334a766a50304d3442446d43763762496e4637316a4753" + - "395546466f2f6c6c6f7a75344c5378774b657373346549494a6b41775a47622b5568467a4c2f374" + - "b323663734f623537794d3562764639784a724c454f624f6b41414141414733666268313257686b" + - "396e4c3455624f36336d73484c5346375639624e3545366a50574666763841715173796d44524b5" + - "948467945306565364774563245554669444678777576354b6c714c594b4a674d6b704241774d41" + - "43514f417570552b4141414141414d4142514b67686745414241514241674541436777414141414" + - "1414141414141593d", result.first().toHexString()) } @Test @@ -145,14 +165,28 @@ class TestSolanaSigner { } ) val params = ConfirmParams.Builder( - asset = Asset(AssetId(Chain.Solana, "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo"), "", "", 8, AssetType.TOKEN), - from = Account(Chain.Solana, "4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S", ""), - amount = BigInteger.valueOf(10_000_000) - ) + asset = Asset( + AssetId(Chain.Solana, "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo"), + "", + "", + 8, + AssetType.TOKEN + ), + from = Account(Chain.Solana, "4Yu2e1Wz5T1Ci2hAPswDqvMgSnJ1Ftw7ZZh8x7xKLx7S", ""), + amount = BigInteger.valueOf(10_000_000) + ) .transfer(destination = DestinationAddress("AGkXQZ9qm99xukisDUHvspWHESrcjs8Y4AmQQgef3BRh")) as ConfirmParams.TransferParams.Token - val chainData = SolanaSignerPreloader.SolanaChainData( + val chainData = SolanaChainData( blockhash = "kiEPF6aKvEsj5nbi4FBvgRRm9ha36Y3cgDU9qnUKt32", - fees = listOf( + recipientTokenAddress = "87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", + senderTokenAddress = "87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", + tokenProgram = SolanaTokenProgramId.Token2022 + ) + val result = runBlocking { + signer.signTokenTransfer( + params, + chainData, + BigInteger.ZERO, GasFee( amount = BigInteger("105005000"), minerFee = BigInteger("1050000000"), @@ -161,23 +195,22 @@ class TestSolanaSigner { feeAssetId = AssetId(Chain.Solana), priority = FeePriority.Normal, ), - ), - recipientTokenAddress = "87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", - senderTokenAddress = "87vTugUvkkepa84mBRfENnvkPQRj5EZSkiG8XyFAhbQQ", - tokenProgram = SolanaTokenProgramId.Token2022 + privateKey + ) + } + assertEquals( + "0x4152744d346e59365642416d427563754c675a7759623165304764516d6b782b6251764f" + + "6241657558466e6a4b5a4744507930653972305249444f384757705056384439453345754b33416" + + "e492b354b6b6d72485667414241414d465365626b44466a2b415242396b4b486b394f4167745057" + + "456e614370426a475a3869707a61372f4e43577470783737467363375a7773776d4234324a65393" + + "04538487a622b59486131534a74465451777a385351705265535344747369697148743063646755" + + "2b566b666b355849514b6e4f505a394e57366654704c696e536541775a47622b5568467a4c2f374" + + "b323663734f623537794d3562764639784a724c454f624f6b41414141414733666268376e575033" + + "68684358627a6b624d33617468723854594f354453662b76666b6f324b474c2f4173796d44524b5" + + "948467945306565364774563245554669444678777576354b6c714c594b4a674d6b704241774d41" + + "43514f417570552b4141414141414d4142514b67686745414241514241674541436777414141414" + + "1414141414141593d", result.first().toHexString() ) - val result = runBlocking { signer.signTokenTransfer(params, chainData, BigInteger.ZERO, FeePriority.Normal, privateKey) } - assertEquals("0x4152744d346e59365642416d427563754c675a7759623165304764516d6b782b6251764f" + - "6241657558466e6a4b5a4744507930653972305249444f384757705056384439453345754b33416" + - "e492b354b6b6d72485667414241414d465365626b44466a2b415242396b4b486b394f4167745057" + - "456e614370426a475a3869707a61372f4e43577470783737467363375a7773776d4234324a65393" + - "04538487a622b59486131534a74465451777a385351705265535344747369697148743063646755" + - "2b566b666b355849514b6e4f505a394e57366654704c696e536541775a47622b5568467a4c2f374" + - "b323663734f623537794d3562764639784a724c454f624f6b41414141414733666268376e575033" + - "68684358627a6b624d33617468723854594f354453662b76666b6f324b474c2f4173796d44524b5" + - "948467945306565364774563245554669444678777576354b6c714c594b4a674d6b704241774d41" + - "43514f417570552b4141414141414d4142514b67686745414241514241674541436777414141414" + - "1414141414141593d", result.first().toHexString()) } @Test diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/stellar/TestStellarSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/stellar/TestStellarSigner.kt index 3c85574ae..0949c1649 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/stellar/TestStellarSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/stellar/TestStellarSigner.kt @@ -1,7 +1,7 @@ package com.gemwallet.android.blockchain.clients.Stellar +import com.gemwallet.android.blockchain.clients.stellar.StellarChainData import com.gemwallet.android.blockchain.clients.stellar.StellarSignClient -import com.gemwallet.android.blockchain.clients.stellar.StellarSignPreloadClient import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset @@ -42,18 +42,16 @@ class TestStellarSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = StellarSignPreloadClient.StellarChainData( - sequence = 1, - fees = listOf( - Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Stellar), - amount = BigInteger.TEN - ), - ), + chainData = StellarChainData( + sequence = 1UL, + isDestinationAddressExist = true, ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Stellar), + amount = BigInteger.TEN + ), privateKey.data(), ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/sui/TestSuiSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/sui/TestSuiSigner.kt index 11fd6eee3..cbf25edf0 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/sui/TestSuiSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/sui/TestSuiSigner.kt @@ -42,21 +42,20 @@ class TestSuiSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = SuiSignerPreloader.SuiChainData( + chainData = SuiChainData( messageBytes = "AAACAAgAypo7AAAAAAAgLuHnHoVlKe7YHnpDy6mnmWueg/fpbWoPf2pUAO0b" + "wWgCAgABAQAAAQEDAAAAAAEBAC7h5x6FZSnu2B56Q8upp5lrnoP36W1qD39qVADtG8F" + "oAS2bHegcizOpgucdlh7PdMz4cCyV89Xv8+pSQHYdUVM07UIbGgAAAAAgbiAG3TMqRi" + "5eRLenwRl5FY6EUk6/RG4a4cjnsc8KNU0u4ecehWUp7tgeekPLqaeZa56D9+ltag9/a" + "lQA7RvBaO4CAAAAAAAAQHh9AQAAAAAA_0xc6af5cd37f2bab89411aff2a642522f88" + "6e3a8bdfea1d0549729e99f3a241bd5", - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Sui), - amount = BigInteger.TEN - ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Sui), + amount = BigInteger.TEN + ), privateKey.data(), ) } @@ -89,7 +88,7 @@ class TestSuiSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = SuiSignerPreloader.SuiChainData( + chainData = SuiChainData( messageBytes = "AAAEAQA+cu/kqxz/pp3Qmo6eoLJz+so76TaSloB1SmEUVhWCaUYoGhwAAAAAI" + "BtZ+Y3WbB+PQtHrS7YgMDZGLzVxrT20trS/6hpbAEmBAQC01EdV46fEpnMdgod7BT2jJ" + "F0uO3bB4vxKQwUM5D5LgUYoGhwAAAAAIG7IzS1+nt9AlH/Ky7M7uvu/hnOkXUjbo13FT" + @@ -99,14 +98,13 @@ class TestSuiSigner { "+S2gTgAQzNMurZ1aIQOw24OKmyO5LC3mt0mBR+cLuHnHoVlKe7YHnpDy6mnmWueg/fpb" + "WoPf2pUAO0bwWjuAgAAAAAAAEB4fQEAAAAAAA==_0xd3877ebdd9f50a6d7d919d6e28" + "a26dd62ec43db0986466a35fa78c84394d3046", - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Sui), - amount = BigInteger.TEN - ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Sui), + amount = BigInteger.TEN + ), privateKey.data(), ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/ton/TestTonSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/ton/TestTonSigner.kt index d2dab1666..530953017 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/ton/TestTonSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/ton/TestTonSigner.kt @@ -42,17 +42,16 @@ class TestTonSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = TonSignerPreloader.TonChainData( - sequence = 1, - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Ton), - amount = BigInteger.TEN - ), + chainData = TonChainData( + sequence = 1UL, expireAt = 1000000000, ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Ton), + amount = BigInteger.TEN + ), privateKey.data(), ) } @@ -81,18 +80,17 @@ class TestTonSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = TonSignerPreloader.TonChainData( - sequence = 1, + chainData = TonChainData( + sequence = 1UL, jettonAddress = "EQAlgB03OjJKdXrlwZiGJD5snSzPKF2VL5bErJn_cqJANGH9", expireAt = 1000000000, - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Ton), - amount = BigInteger.TEN - ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Ton), + amount = BigInteger.TEN + ), privateKey.data(), ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronAccountService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronAccountService.kt deleted file mode 100644 index 68094d89b..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronAccountService.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.tron.services.TronAccountsService -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.blockchain.tron.TronAccountRequest -import com.wallet.core.blockchain.tron.TronAccountUsage - -class FakeTronAccountService( - private val tronAccount: TronAccount? = null -) : TronAccountsService { - var accountRequest: TronAccountRequest? = null - var usageRequest: TronAccountRequest? = null - - override suspend fun getAccount(addressRequest: TronAccountRequest): Result { - this.accountRequest = addressRequest - return Result.success(tronAccount ?: return Result.failure(Exception())) - } - - override suspend fun getAccountUsage(addressRequest: TronAccountRequest): Result { - this.usageRequest = addressRequest - - return Result.success( - TronAccountUsage( - freeNetUsed = 1, - freeNetLimit = 2, - ) - ) - } - - -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronCallService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronCallService.kt deleted file mode 100644 index daa6a7a0b..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronCallService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.tron.services.TronCallService -import com.wallet.core.blockchain.tron.TronSmartContractResult - -class FakeTronCallService( - val responses: Map = emptyMap() -) : TronCallService { - val requests = mutableListOf>() - - override suspend fun triggerSmartContract(request: Any): Result { - requests.add(request as Map) - return Result.success(responses[request["contract_address"] ?: throw Exception()] - ?: return Result.failure(Exception())) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronNodeStatusService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronNodeStatusService.kt deleted file mode 100644 index 9afc7fe6f..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronNodeStatusService.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.tron.services.TronNodeStatusService -import com.wallet.core.blockchain.tron.TronBlock -import com.wallet.core.blockchain.tron.TronChainParameter -import com.wallet.core.blockchain.tron.TronChainParameters -import com.wallet.core.blockchain.tron.TronHeader -import com.wallet.core.blockchain.tron.TronHeaderRawData -import retrofit2.Response - -private val chainParamters = TronChainParameters( - listOf( - TronChainParameter("getCreateNewAccountFeeInSystemContract", 1000000), - TronChainParameter("getCreateAccountFee", 100000), - TronChainParameter("getEnergyFee", 210), - ) -) - -class FakeTronNodeStatusService( - private val chainParameters: TronChainParameters? = chainParamters, - private val tronBlock: TronBlock? = TronBlock( - TronHeaderRawData( - TronHeader( - number = 67978303, - version = 31, - txTrieRoot = "e02c6d0bab5f0c6d1f61051646535ed76f6e1ef0db5c32069cf612123ce976b3", - witness_address = "41c05142fd1ca1e03688a43585096866ae658f2cb2", - parentHash = "00000000040d443e37c9fcdfb11ba6fb9ed08682f0f492b3b4ab6639b9198694", - timestamp = 1734585603000, - ) - ) - ), -) : TronNodeStatusService { - - override suspend fun getChainParameters(): Result { - return Result.success(chainParameters ?: return Result.failure(Exception())) - } - - override suspend fun nowBlock(): Result { - return Result.success(tronBlock ?: return Result.failure(Exception())) - } - - override suspend fun nowBlock(url: String): Response { - TODO("Not yet implemented") - } - - -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronStakeService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronStakeService.kt deleted file mode 100644 index c84a3f286..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/FakeTronStakeService.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.tron.services.TronStakeService -import com.wallet.core.blockchain.tron.TronReward -import com.wallet.core.blockchain.tron.WitnessesList - -class FakeTronStakeService( - private val reward: Long? = null -) : TronStakeService { - var addressRequest: String? = null - - - override suspend fun listwitnesses(): Result { - TODO("Not yet implemented") - } - - override suspend fun getReward(address: String): Result { - addressRequest = address - return Result.success(TronReward(reward ?: return Result.failure(Exception()))) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronBalance.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronBalance.kt deleted file mode 100644 index 642d0fa79..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronBalance.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.includeLibs -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.blockchain.tron.TronFrozen -import com.wallet.core.blockchain.tron.TronSmartContractResult -import com.wallet.core.blockchain.tron.TronSmartContractResultMessage -import com.wallet.core.blockchain.tron.TronUnfrozen -import com.wallet.core.blockchain.tron.TronVote -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertNull -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import org.junit.Test - -class TestTronBalance { - companion object { - init { - includeLibs() - } - } - - val stakeService = FakeTronStakeService(0xF4240) - - @Test - fun testTron_native_balance_success_and_not_empty() { - val accountService = FakeTronAccountService( - TronAccount( - balance = 1_000_000, - ) - ) - val callService = FakeTronCallService() - val balanceClient = TronBalanceClient(Chain.Tron, accountService, callService, FakeTronStakeService()) - val result = runBlocking { balanceClient.getNativeBalance(Chain.Tron, "TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU") } - assertEquals("TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU", accountService.accountRequest?.address) - assertTrue(accountService.accountRequest!!.visible) - assertNotNull(result) - assertEquals(AssetId(Chain.Tron), result!!.asset.id) - assertEquals("1000000", result.balance.available) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.pending) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.rewards) - assertEquals(1.0, result.balanceAmount.available) - assertEquals(1.0, result.totalAmount) - } - - @Test - fun testTron_native_balance_success_and_empty() { - val accountService = FakeTronAccountService( - TronAccount() - ) - val callService = FakeTronCallService() - val balanceClient = TronBalanceClient(Chain.Tron, accountService, callService, FakeTronStakeService()) - val result = runBlocking { balanceClient.getNativeBalance(Chain.Tron, "TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU") } - assertNull(result) - } - - @Test - fun testTron_native_balance_fail() { - val accountService = FakeTronAccountService() - val callService = FakeTronCallService() - val balanceClient = TronBalanceClient(Chain.Tron, accountService, callService, stakeService) - val result = runBlocking { balanceClient.getNativeBalance(Chain.Tron, "") } - assertNull(result) - } - - @Test - fun testTron_token_balance_success() { - val assets = listOf( - Asset( - id = AssetId(Chain.Tron, "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"), - decimals = 6, - name = "Tether USD", - symbol = "USDT", - type = AssetType.TRC20, - ), - Asset( - id = AssetId(Chain.Tron, "TAFjULxiVgT4qWk6UZwjqwZXTSaGaqnVp4"), - decimals = 18, - name = "BitTorrent", - symbol = "BTT", - type = AssetType.TRC20, - ), - Asset( - id = AssetId(Chain.Tron, "TG6jUMfwpwR9QNFsSwCGtLaV2TR2gV8yru"), - decimals = 6, - name = "Wrapped TRX", - symbol = "WTRX", - type = AssetType.TRC20, - ), - ) - val accountService = FakeTronAccountService(TronAccount(balance = 1_000_000)) - val callService = FakeTronCallService( - mapOf( - "41a614f803b6fd780986a42c78ec9c7f77e6ded13c" to TronSmartContractResult( - result = TronSmartContractResultMessage(true), - constant_result = listOf("F4240"), - energy_used = 1, - ), - "41032017411f4663b317fe77c257d28d5cd1b26e3d" to TronSmartContractResult( - result = TronSmartContractResultMessage(true), - constant_result = listOf("DE0B6B3A7640000"), - energy_used = 1, - ), - "41433d1a20a144c3b064e9371bca739f960900f409" to TronSmartContractResult( - result = TronSmartContractResultMessage(true), - constant_result = listOf("3000000"), - energy_used = 1, - ), - ) - ) - val balanceClient = TronBalanceClient(Chain.Tron, accountService, callService, stakeService) - val result = runBlocking { balanceClient.getTokenBalances(Chain.Tron, "TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU", assets) } - assertEquals("41a614f803b6fd780986a42c78ec9c7f77e6ded13c", callService.requests[0]["contract_address"]) - assertEquals("41032017411f4663b317fe77c257d28d5cd1b26e3d", callService.requests[1]["contract_address"]) - assertEquals("41433d1a20a144c3b064e9371bca739f960900f409", callService.requests[2]["contract_address"]) - assertEquals(false, callService.requests[0]["visible"]) - assertEquals(0L, callService.requests[0]["call_value"]) - assertEquals("4187b59ec7bb58250533fb8235f9a3f8eec9c1bfe8", callService.requests[0]["owner_address"]) - assertEquals(1_000_000L, callService.requests[0]["fee_limit"]) - assertEquals("balanceOf(address)", callService.requests[0]["function_selector"]) - assertEquals("00000000000000000000004187b59ec7bb58250533fb8235f9a3f8eec9c1bfe8", callService.requests[0]["parameter"]) - - assertNotNull(result) - assertEquals(3, result.size) - assertEquals("1000000", result[0].balance.available) - assertEquals(1.0, result[0].balanceAmount.available) - assertEquals("1000000000000000000", result[1].balance.available) - assertEquals(1.0, result[1].balanceAmount.available) - assertEquals("50331648", result[2].balance.available) - assertEquals(50.331648, result[2].balanceAmount.available) - } - - @Test - fun testTron_stake_balance_success() { - val accountService = FakeTronAccountService( - TronAccount( - balance = 1_000_000, - frozenV2 = listOf( - TronFrozen( - amount = 0xF4240, - ), - TronFrozen( - amount = 0x1E8480, - ), - ), - unfrozenV2 = listOf( - TronUnfrozen( - unfreeze_amount = 0x2DC6C0 - ), - TronUnfrozen( - unfreeze_amount = 0x3D0900 - ), - ), - votes = listOf( - TronVote( - vote_address = "", - vote_count = 1, - ), - TronVote( - vote_address = "", - vote_count = 2, - ), - TronVote( - vote_address = "", - vote_count = 3, - ), - ) - ) - ) - val callService = FakeTronCallService() - val balanceClient = TronBalanceClient(Chain.Tron, accountService, callService, stakeService) - val result = runBlocking { balanceClient.getNativeBalance(Chain.Tron, "TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU") } - assertNotNull(result) - assertEquals(AssetId(Chain.Tron), result!!.asset.id) - assertEquals("1000000", result.balance.available) - assertEquals("6000000", result.balance.staked) - assertEquals("7000000", result.balance.pending) - assertEquals("0", result.balance.reserved) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.frozen) - assertEquals("1000000", result.balance.rewards) - assertEquals(1.0, result.balanceAmount.available) - assertEquals(6.0, result.balanceAmount.staked) - assertEquals(7.0, result.balanceAmount.pending) - assertEquals(1.0, result.balanceAmount.rewards) - assertEquals(15.0, result.totalAmount) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronFeeCalculator.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronFeeCalculator.kt deleted file mode 100644 index 6066fdc3b..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronFeeCalculator.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.blockchain.tron.TronAccountUsage -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestTronFeeCalculator { - companion object { - init { - includeLibs() - } - } - - @Test - fun testTron_native_transfer_fee() { - val feeCalculator = TronFeeCalculator( - chain = Chain.Tron, - nodeStatusService = FakeTronNodeStatusService(), - callService = FakeTronCallService() - ) - - val params: ConfirmParams.TransferParams.Native = ConfirmParams.Builder( - Chain.Tron.asset(), - Account(Chain.Tron, "TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU", ""), - BigInteger.valueOf(1_000_000) - ).transfer(destination = DestinationAddress("THdHCD2miVcUdqAt32168a6wiyG5CE6WRY")) as ConfirmParams.TransferParams.Native - val result = runBlocking { - feeCalculator.calculate( - params, - TronAccount(address = "TNLmo9j9AuGnnxibQUT13xoMGuUmNwxtkU"), - TronAccountUsage() - ) - } - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronSigner.kt index 96a31d1c6..7764ae8f0 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/tron/TestTronSigner.kt @@ -42,22 +42,21 @@ class TestTronSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = TronSignerPreloader.TronChainData( - number = 69501435, - version = 31, + chainData = TronChainData( + blockNumber = 69501435UL, + blockVersion = 31UL, txTrieRoot = "fe35cfe51299075978398390271d3f09bdc34e6f43fe8b76eb469314b32ceaff", witnessAddress = "41456798cb4ab28109d8cc643cd7da7bd6069ceae9", parentHash = "00000000042481fa52ef745a31aa66fc2acf8d156b6116bc5b3ede2aebbb894c", - timestamp = 1739156280000, + blockTimestamp = 1739156280000UL, votes = emptyMap(), - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Tron), - amount = BigInteger.TEN - ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Tron), + amount = BigInteger.TEN + ), privateKey.data(), ) } @@ -96,22 +95,21 @@ class TestTronSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = TronSignerPreloader.TronChainData( - number = 69501435, - version = 31, + chainData = TronChainData( + blockNumber = 69501435UL, + blockVersion = 31UL, txTrieRoot = "fe35cfe51299075978398390271d3f09bdc34e6f43fe8b76eb469314b32ceaff", witnessAddress = "41456798cb4ab28109d8cc643cd7da7bd6069ceae9", parentHash = "00000000042481fa52ef745a31aa66fc2acf8d156b6116bc5b3ede2aebbb894c", - timestamp = 1739156280000, + blockTimestamp = 1739156280000UL, votes = emptyMap(), - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Tron), - amount = BigInteger.TEN - ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Tron), + amount = BigInteger.TEN + ), privateKey.data(), ) } @@ -154,25 +152,24 @@ class TestTronSigner { BigInteger.valueOf(10_000), validatorId = "TCEo1hMAdaJrQmvnGTCcGT2LqrGU4N7Jqf", ), - chainData = TronSignerPreloader.TronChainData( - number = 69501435, - version = 31, + chainData = TronChainData( + blockNumber = 69501435UL, + blockVersion = 31UL, txTrieRoot = "fe35cfe51299075978398390271d3f09bdc34e6f43fe8b76eb469314b32ceaff", witnessAddress = "41456798cb4ab28109d8cc643cd7da7bd6069ceae9", parentHash = "00000000042481fa52ef745a31aa66fc2acf8d156b6116bc5b3ede2aebbb894c", - timestamp = 1739156280000, + blockTimestamp = 1739156280000UL, votes = mapOf( - "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH" to 1, - "TCEo1hMAdaJrQmvnGTCcGT2LqrGU4N7Jqf" to 1, - ), - fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Tron), - amount = BigInteger.TEN + "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH" to 1UL, + "TCEo1hMAdaJrQmvnGTCcGT2LqrGU4N7Jqf" to 1UL, ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Tron), + amount = BigInteger.TEN + ), privateKey.data(), ) } diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpAccountsService.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpAccountsService.kt deleted file mode 100644 index 66956d129..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpAccountsService.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.xrp.services.XrpAccountsService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.wallet.core.blockchain.xrp.XRPAccount -import com.wallet.core.blockchain.xrp.XRPAccountLinesResult -import com.wallet.core.blockchain.xrp.XRPAccountResult -import com.wallet.core.blockchain.xrp.XRPResult - -internal class TestXrpAccountsService( - val balance: String = "", -) : XrpAccountsService { - var requestAccount: String? = "" - - override suspend fun account(request: JSONRpcRequest>>): Result> { - requestAccount = request.params[0]["account"] - return Result.success( - XRPResult( - XRPAccountResult( - XRPAccount( - Balance = balance, - Sequence = 92788459, - OwnerCount = 1, - ), - ledger_current_index = 1 - ) - ) - ) - } - - override suspend fun accountLines(request: JSONRpcRequest>>): Result> { - return Result.success( - XRPResult( - XRPAccountLinesResult( - listOf() - ) - ) - ) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpBalanceClient.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpBalanceClient.kt deleted file mode 100644 index f1147aa8c..000000000 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpBalanceClient.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.includeLibs -import com.gemwallet.android.ext.toIdentifier -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import kotlinx.coroutines.runBlocking -import org.junit.Test - -class TestXrpBalanceClient { - companion object { - init { - includeLibs() - } - } - - @Test - fun testXrp_native_balance() { - val accountsService = TestXrpAccountsService("2104374") - val balanceClient = XrpBalanceClient( - chain = Chain.Xrp, - accountsService = accountsService - ) - val result = runBlocking { - balanceClient.getNativeBalance(Chain.Xrp, "rwCq6DCHa6HPFyfvabvzcX1y5wABw5KdiN") - } - assertEquals("rwCq6DCHa6HPFyfvabvzcX1y5wABw5KdiN", accountsService.requestAccount) - assertNotNull(result) - assertEquals("1104374", result!!.balance.available) - assertEquals("0", result.balance.frozen) - assertEquals("0", result.balance.locked) - assertEquals("0", result.balance.staked) - assertEquals("0", result.balance.rewards) - assertEquals("1000000", result.balance.reserved) - assertEquals("0", result.balance.pending) - assertEquals(1.104374, result.balanceAmount.available) - assertEquals(0.0, result.balanceAmount.frozen) - assertEquals(0.0, result.balanceAmount.locked) - assertEquals(0.0, result.balanceAmount.staked) - assertEquals(0.0, result.balanceAmount.rewards) - assertEquals(1.0, result.balanceAmount.reserved) - assertEquals(0.0, result.balanceAmount.pending) - assertEquals(1.104374, result.totalAmount) - assertEquals(AssetId(Chain.Xrp).toIdentifier(), result.asset.id.toIdentifier()) - } -} \ No newline at end of file diff --git a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpSigner.kt b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpSigner.kt index a7ffac955..b5f4b1eb8 100644 --- a/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpSigner.kt +++ b/blockchain/src/androidTest/kotlin/com/gemwallet/android/blockchain/clients/xrp/TestXrpSigner.kt @@ -3,7 +3,6 @@ package com.gemwallet.android.blockchain.clients.xrp import com.gemwallet.android.blockchain.includeLibs import com.gemwallet.android.blockchain.testPhrase import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.DestinationAddress import com.gemwallet.android.model.Fee @@ -40,19 +39,16 @@ class TestXrpSigner { BigInteger.valueOf(10_000), DestinationAddress(from), ), - chainData = XrpSignerPreloader.XrpChainData( + chainData = XrpChainData( sequence = 1, blockNumber = 1, - fees = listOf( - Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(Chain.Xrp), - amount = BigInteger.TEN, - ) - ), ), finalAmount = BigInteger.valueOf(10_000), - FeePriority.Normal, + fee = Fee( + priority = FeePriority.Normal, + feeAssetId = AssetId(Chain.Xrp), + amount = BigInteger.TEN, + ), privateKey.data(), ) } @@ -63,7 +59,7 @@ class TestXrpSigner { "d5b18dd75818a07d4b4ed5846b07604e48607789d393691334f59d3761f6874c02205ac35c8b" + "cadb9fdbd81022f3629bfa0aac0b80afa655628c8ddbfee030f1bb178114dd10693e412bff78" + "9ebf6baa9714036c9ae214bb8314dd10693e412bff789ebf6baa9714036c9ae214bb", - sign.first().toHexString() + String(sign.first()) ) } } \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BalanceClient.kt deleted file mode 100644 index c051d4970..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BalanceClient.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain - -interface BalanceClient : BlockchainClient { - suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? - - suspend fun getDelegationBalances(chain: Chain, address: String): AssetBalance? = null - - suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List = emptyList() -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BroadcastClient.kt deleted file mode 100644 index 7420741e2..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BroadcastClient.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.TransactionType - -interface BroadcastClient : BlockchainClient { - suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BroadcastClientProxy.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BroadcastClientProxy.kt deleted file mode 100644 index 13aed8501..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/BroadcastClientProxy.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class BroadcastClientProxy( - private val clients: List, -) : BroadcastClient { - - override suspend fun send( - account: Account, - signedMessage: ByteArray, - type: TransactionType - ): String { - return clients.getClient(account.chain)?.send(account, signedMessage, type) - ?: throw Exception("Chain isn't support") - } - - override fun supported(chain: Chain): Boolean { - return clients.getClient(chain) != null - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/GetTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/GetTokenClient.kt deleted file mode 100644 index f4ce113ba..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/GetTokenClient.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.wallet.core.primitives.Asset - -interface GetTokenClient : BlockchainClient { - suspend fun getTokenData(tokenId: String): Asset? - - suspend fun isTokenQuery(query: String): Boolean -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/NodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/NodeStatusClient.kt deleted file mode 100644 index fe6bd81c7..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/NodeStatusClient.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain - -interface NodeStatusClient : BlockchainClient { - suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/NodeStatusClientProxy.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/NodeStatusClientProxy.kt deleted file mode 100644 index 0fb3559eb..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/NodeStatusClientProxy.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain - -class NodeStatusClientProxy( - private val clients: List, -): NodeStatusClient { - - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? { - return try { - clients.getClient(chain)?.getNodeStatus(chain, url) - } catch (_: Throwable) { - null - } - } - - override fun supported(chain: Chain): Boolean { - return clients.getClient(chain) != null - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClient.kt index 6e596e0c5..c3ed56192 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClient.kt @@ -2,8 +2,8 @@ package com.gemwallet.android.blockchain.clients import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import java.math.BigInteger interface SignClient : BlockchainClient { @@ -20,7 +20,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.TransferParams.Generic, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -28,7 +28,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -36,7 +36,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -44,7 +44,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -52,7 +52,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.TokenApprovalParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -60,7 +60,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.Stake.DelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -68,7 +68,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.Stake.UndelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -76,7 +76,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.Stake.RedelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -84,7 +84,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.Stake.RewardsParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -92,7 +92,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.Stake.WithdrawParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -100,7 +100,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.Activate, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() @@ -108,7 +108,7 @@ interface SignClient : BlockchainClient { params: ConfirmParams.NftParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray, ): List = emptyList() } \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/StakeClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/StakeClient.kt deleted file mode 100644 index 7c9ad7795..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/StakeClient.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationValidator - -interface StakeClient : BlockchainClient { - suspend fun getValidators(chain: Chain, apr: Double): List - - suspend fun getStakeDelegations(chain: Chain, address: String, apr: Double): List -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/StakeClientProxy.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/StakeClientProxy.kt deleted file mode 100644 index 28e038b01..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/StakeClientProxy.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationValidator - -class StakeClientProxy( - private val clients: List -) : StakeClient { - override suspend fun getValidators( - chain: Chain, - apr: Double - ): List { - return clients.getClient(chain)?.getValidators(chain, apr) ?: emptyList() - } - - override suspend fun getStakeDelegations( - chain: Chain, - address: String, - apr: Double - ): List { - return clients.getClient(chain)?.getStakeDelegations(chain, address, apr) ?: emptyList() - } - - override fun supported(chain: Chain): Boolean { - return clients.getClient(chain) != null - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/TransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/TransactionStatusClient.kt deleted file mode 100644 index d33d5db7c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/TransactionStatusClient.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.gemwallet.android.blockchain.clients - -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain - -interface TransactionStatusClient : BlockchainClient { - - suspend fun getStatus(request: TransactionStateRequest): TransactionChanges -} - -class TransactionStateRequest( - val chain: Chain, - val hash: String, - val block: String, - val sender: String, -) - -sealed class TransactionStatusError(message: String? = null) : Exception(message) - -data object ServiceUnavailable : TransactionStatusError() - -class TransactionError(message: String) : TransactionStatusError(message) - -class TransactionNotFound(message: String? = null) : TransactionStatusError(message) \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandBalanceClient.kt deleted file mode 100644 index 11fbe981e..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandBalanceClient.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.algorand.services.AlgorandAccountService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Chain -import kotlin.math.max - -class AlgorandBalanceClient( - private val chain: Chain, - private val accountService: AlgorandAccountService, -) : BalanceClient { - - override suspend fun getNativeBalance( - chain: Chain, - address: String - ): AssetBalance? { - val response = accountService.accounts(address).getOrNull() ?: return null - val amount = response.amount - - val available = if (amount > 0L) { - max(amount - response.min_balance, 0L).toString() - } else { - "0" - } - val reserved = if (response.amount > 0L) { - response.min_balance.toString() - } else { - "0" - } - return AssetBalance.create(chain.asset(), available = available, reserved = reserved.toString()) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandBroadcastClient.kt deleted file mode 100644 index c84b8e2d1..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandBroadcastClient.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.algorand.services.AlgorandBroadcastService -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.blockchain.rpc.handleError -import com.wallet.core.blockchain.algorand.AlgorandTransactionBroadcast -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import okhttp3.RequestBody.Companion.toRequestBody - -class AlgorandBroadcastClient( - private val chain: Chain, - private val broadcastService: AlgorandBroadcastService, -) : BroadcastClient { - - override suspend fun send( - account: Account, - signedMessage: ByteArray, - type: TransactionType - ): String { - val result = broadcastService.broadcast(signedMessage.toRequestBody(Mime.Binary.value)) - return result.getOrNull()?.txId ?: throw - result.handleError()?.message?.let { Exception(it) } - ?: ServiceError.BroadCastError() - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandChainData.kt new file mode 100644 index 000000000..da07ecd8d --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandChainData.kt @@ -0,0 +1,18 @@ +package com.gemwallet.android.blockchain.clients.algorand + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class AlgorandChainData( + val sequence: ULong, + val block: String, + val chainId: String, +) : ChainSignData + +fun GemTransactionLoadMetadata.Algorand.toChainData(): AlgorandChainData { + return AlgorandChainData( + sequence = sequence, + block = blockHash, + chainId = chainId, + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandNodeStatusClient.kt deleted file mode 100644 index 6e93ab94d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandNodeStatusClient.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.algorand.services.AlgorandNodeStatusService -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain - -class AlgorandNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: AlgorandNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus( - chain: Chain, - url: String - ): NodeStatus? { - val resp = try { - nodeStatusService.transactionsParams("$url/v2/transactions/params") - } catch (err: Throwable) { - throw err - } - val result = resp.body() - return NodeStatus( - url = url, - blockNumber = result?.last_round?.toString() ?: return null, - inSync = true, - chainId = result.genesis_id, - latency = resp.getLatency() - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignClient.kt index 195e16ce2..c90649380 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignClient.kt @@ -2,11 +2,12 @@ package com.gemwallet.android.blockchain.clients.algorand import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy +import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.java.AnySigner import wallet.core.jni.Base64 import wallet.core.jni.proto.Algorand @@ -20,10 +21,10 @@ class AlgorandSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = (chainData as? AlgorandSignPreloadClient.AlgorandChainData) + val chainData = (chainData as? AlgorandChainData) ?: throw Exception("bad params") val input = Algorand.SigningInput.newBuilder().apply { this.genesisId = chainData.chainId @@ -33,7 +34,7 @@ class AlgorandSignClient( } this.firstRound = chainData.sequence.toLong() this.lastRound = chainData.sequence.toLong() + 1000 - this.fee = chainData.fee().amount.toLong() + this.fee = fee.amount.toLong() this.privateKey = ByteString.copyFrom(privateKey) this.transfer = Algorand.Transfer.newBuilder().apply { this.toAddress = params.destination().address @@ -44,7 +45,7 @@ class AlgorandSignClient( if (!output.errorMessage.isNullOrEmpty()) { throw Exception(output.errorMessage) } - return listOf(output.encoded.toByteArray()) + return listOf(output.encoded.toByteArray().toHexString("").toByteArray()) } override fun supported(chain: Chain): Boolean = this.chain == chain diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignPreloadClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignPreloadClient.kt deleted file mode 100644 index 9bce5cada..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandSignPreloadClient.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.algorand.services.AlgorandNodeStatusService -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority - -class AlgorandSignPreloadClient( - private val chain: Chain, - private val feeService: AlgorandNodeStatusService, -) : NativeTransferPreloader { - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - val txParams = feeService.transactionsParams().getOrNull() ?: throw Exception("fee load error") - val fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(chain), - amount = txParams.min_fee.toBigInteger(), - ) - return SignerParams( - input = params, - chainData = AlgorandChainData( - sequence = txParams.last_round.toInt(), - block = txParams.genesis_hash, - chainId = txParams.genesis_id, - fee = fee - ) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class AlgorandChainData( - val sequence: Int, - val block: String, - val chainId: String, - val fee: Fee, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandTransactionStatusClient.kt deleted file mode 100644 index 7579e968d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/AlgorandTransactionStatusClient.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.algorand.services.AlgorandTxStatusService -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class AlgorandTransactionStatusClient( - private val chain: Chain, - private val txStatusService: AlgorandTxStatusService, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val round = txStatusService.transaction(request.hash).getOrNull()?.confirmed_round ?: throw ServiceUnavailable - return TransactionChanges(if (round > 0) TransactionState.Confirmed else TransactionState.Failed) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandAccountService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandAccountService.kt deleted file mode 100644 index 3cf7b0c0b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandAccountService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand.services - -import com.wallet.core.blockchain.algorand.AlgorandAccount -import retrofit2.http.GET -import retrofit2.http.Path - -interface AlgorandAccountService { - @GET("/v2/accounts/{address}") - suspend fun accounts(@Path("address") address: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandBroadcastService.kt deleted file mode 100644 index db63e7699..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandBroadcastService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand.services - -import com.wallet.core.blockchain.algorand.AlgorandTransactionBroadcast -import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.POST - -interface AlgorandBroadcastService { - - @POST("/v2/transactions") - suspend fun broadcast(@Body body: RequestBody): Result - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandNodeStatusService.kt deleted file mode 100644 index 573df27e9..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandNodeStatusService.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand.services - -import com.wallet.core.blockchain.algorand.AlgorandTransactionParams -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Url - -interface AlgorandNodeStatusService { - @GET("/v2/transactions/params") - suspend fun transactionsParams(): Result - - @GET//("/v2/transactions/params") - suspend fun transactionsParams(@Url url: String): Response -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandService.kt deleted file mode 100644 index 92d639c7b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandService.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand.services - -interface AlgorandService : AlgorandAccountService, - AlgorandBroadcastService, - AlgorandTxStatusService, - AlgorandNodeStatusService \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandTxStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandTxStatusService.kt deleted file mode 100644 index b80e8a23d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/algorand/services/AlgorandTxStatusService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.algorand.services - -import com.wallet.core.blockchain.algorand.AlgorandTransactionStatus -import retrofit2.http.GET -import retrofit2.http.Path - -interface AlgorandTxStatusService { - @GET("/v2/transactions/pending/{id}") - suspend fun transaction(@Path("id") id: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosBalanceClient.kt deleted file mode 100644 index 63d9530c2..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosBalanceClient.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.aptos.services.AptosBalancesService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.withContext - -class AptosBalanceClient( - private val chain: Chain, - private val balanceService: AptosBalancesService, -) : BalanceClient { - private val aptosCoin = "0x1::aptos_coin::AptosCoin" - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - return try { - val result = balanceService.balance(address, aptosCoin).string() - AssetBalance.create(chain.asset(), available = result) - } catch (_: Throwable) { - null - } - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - if (tokens.isEmpty()) { - return emptyList() - } - return withContext(Dispatchers.IO) { - tokens.map { token -> - async { - val tokenId = token.id.tokenId ?: return@async null - try { - val result = balanceService.balance(address, tokenId).string() - AssetBalance.create(token, available = result) - } catch (_: Throwable) { - null - } - } - } - .awaitAll() - .filterNotNull() - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosBroadcastClient.kt deleted file mode 100644 index 0fe9910c0..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosBroadcastClient.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.aptos.services.AptosBroadcastService -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import okhttp3.RequestBody.Companion.toRequestBody - -class AptosBroadcastClient( - private val chain: Chain, - private val broadcastService: AptosBroadcastService, -) : BroadcastClient { - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - return broadcastService.broadcast(String(signedMessage).toRequestBody(Mime.Json.value)) - .getOrThrow() - .hash - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosChainData.kt new file mode 100644 index 000000000..827ad1636 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosChainData.kt @@ -0,0 +1,14 @@ +package com.gemwallet.android.blockchain.clients.aptos + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class AptosChainData( + val sequence: ULong, +) : ChainSignData + +fun GemTransactionLoadMetadata.Aptos.toChainData(): AptosChainData { + return AptosChainData( + sequence = sequence, + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosFeeCalculator.kt deleted file mode 100644 index 61a77e3b1..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosFeeCalculator.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.aptos.services.AptosFeeService -import com.gemwallet.android.ext.type -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.GasFee -import com.wallet.core.blockchain.aptos.AptosSignature -import com.wallet.core.blockchain.aptos.AptosTransaction -import com.wallet.core.blockchain.aptos.AptosTransactionPayload -import com.wallet.core.blockchain.aptos.AptosTransactionSimulation -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetSubtype -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.withContext -import java.math.BigInteger - -internal class AptosFeeCalculator( - private val chain: Chain, - private val feeRpcClient: AptosFeeService, -) { - private val maxGasAmount = BigInteger.valueOf(1_500) - - suspend fun calculate(params: ConfirmParams, sequence: Long): List = withContext(Dispatchers.IO) { - val feePrice = feeRpcClient.feePrice().getOrThrow() - - FeePriority.entries.map { - async(Dispatchers.IO) { - val price = when (it) { - FeePriority.Slow -> feePrice.gas_estimate - FeePriority.Normal -> feePrice.prioritized_gas_estimate - FeePriority.Fast -> feePrice.prioritized_gas_estimate * 2 - }.toBigInteger() - - val gasLimit = when (params) { - is ConfirmParams.TransferParams -> { - val recipient = params.destination().address - when (params.asset.id.type()) { - AssetSubtype.NATIVE -> simulateTransactions( - sender = params.from.address, - recipient = recipient, - sequence = sequence, - value = params.amount, - gasPrice = price, - maxGasAmount = maxGasAmount - ).gas_used.toBigInteger() - - AssetSubtype.TOKEN -> maxGasAmount - } - } - is ConfirmParams.SwapParams -> maxGasAmount - else -> throw IllegalArgumentException("not supported operation") - } - - GasFee( - feeAssetId = AssetId(chain), - priority = it, - maxGasPrice = price, - limit = gasLimit, - ) - } - }.awaitAll() - } - - private suspend fun simulateTransactions( - sender: String, - recipient: String, - sequence: Long, - value: BigInteger, - gasPrice: BigInteger, - maxGasAmount: BigInteger - ): AptosTransaction { - val transaction = AptosTransactionSimulation( - expiration_timestamp_secs = (System.currentTimeMillis() / 1_000 + 1_000_000).toString(), - gas_unit_price = gasPrice.toString(), - max_gas_amount = maxGasAmount.toString(), - payload = AptosTransactionPayload( - arguments = listOf( - recipient, - value.toString(), - ), - function = "0x1::aptos_account::transfer", - type = "entry_function_payload", - type_arguments = emptyList(), - ), - sender = sender, - sequence_number = sequence.toString(), - signature = AptosSignature( - type = "no_account_signature", - public_key = null, - signature = null, - ), - ) - val response = feeRpcClient.simulate(transaction) - val simulated = response.getOrNull()?.firstOrNull() - return simulated ?: throw Exception("No aptos transaction") - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosGetTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosGetTokenClient.kt deleted file mode 100644 index 1e160a794..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosGetTokenClient.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.GetTokenClient -import com.gemwallet.android.blockchain.clients.aptos.services.AptosTokensService -import com.gemwallet.android.math.has0xPrefix -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain - -class AptosGetTokenClient( - private val chain: Chain, - private val tokensService: AptosTokensService, -) : GetTokenClient { - - override suspend fun getTokenData(tokenId: String): Asset? { - val address = tokenId.split("::").firstOrNull() ?: return null - val resource = "0x1::coin::CoinInfo<$tokenId>" - val tokenInfo = tokensService.resource(address, resource).getOrNull()?.data ?: return null - return Asset( - id = AssetId(chain, tokenId), - name = tokenInfo.name, - symbol = tokenInfo.symbol, - decimals = tokenInfo.decimals, - type = AssetType.TOKEN - ) - } - - override suspend fun isTokenQuery(query: String): Boolean = isTokenAddress(query) - - override fun supported(chain: Chain): Boolean = chain == this.chain - - companion object { - fun isTokenAddress(tokenId: String): Boolean { - return tokenId.has0xPrefix() && tokenId.contains("::") - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosNodeStatusClient.kt deleted file mode 100644 index 56480f75c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosNodeStatusClient.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.aptos.services.AptosNodeStatusService -import com.gemwallet.android.blockchain.clients.aptos.services.getLedger -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class AptosNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: AptosNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val response = nodeStatusService.getLedger(url) - val ledger = response.body() ?: return@withContext null - NodeStatus( - url = url, - chainId = ledger.chain_id.toString(), - blockNumber = ledger.ledger_version, - inSync = true, - latency = response.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignClient.kt index 621dea295..ef5f8cd4d 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignClient.kt @@ -4,9 +4,10 @@ import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee +import com.gemwallet.android.model.GasFee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.java.AnySigner import wallet.core.jni.proto.Aptos import wallet.core.jni.proto.Aptos.TokenTransferCoinsMessage @@ -23,35 +24,34 @@ class AptosSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return sign(params, chainData, privateKey, buildTransferMessage(params, finalAmount)) + return sign(params, chainData, fee as GasFee, privateKey, buildTransferMessage(params, finalAmount)) } override suspend fun signTokenTransfer( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return sign(params, chainData, privateKey, buildTokenCoinMessage(params, finalAmount)) + return sign(params, chainData, fee as GasFee, privateKey, buildTokenCoinMessage(params, finalAmount)) } override suspend fun signSwap( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return sign(params, chainData, privateKey, params.swapData) + return sign(params, chainData, fee as GasFee, privateKey, params.swapData) } - private fun sign(params: ConfirmParams, chainData: ChainSignData, privateKey: ByteArray, message: Any): List { - val metadata = chainData as AptosSignerPreloader.AptosChainData - val fee = metadata.gasFee() + private fun sign(params: ConfirmParams, chainData: ChainSignData, fee: GasFee, privateKey: ByteArray, message: Any): List { + val metadata = chainData as AptosChainData val signInput = Aptos.SigningInput.newBuilder().apply { this.chainId = 1 when (message) { @@ -63,7 +63,7 @@ class AptosSignClient( this.expirationTimestampSecs = 3664390082 this.gasUnitPrice = fee.maxGasPrice.toLong() this.maxGasAmount = fee.limit.toLong() - this.sequenceNumber = metadata.sequence + this.sequenceNumber = metadata.sequence.toLong() this.sender = params.from.address this.privateKey = ByteString.copyFrom(privateKey) }.build() diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignerPreloader.kt deleted file mode 100644 index a396aa9cc..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosSignerPreloader.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.aptos.services.AptosAccountsService -import com.gemwallet.android.blockchain.clients.aptos.services.AptosFeeService -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority - -class AptosSignerPreloader( - private val chain: Chain, - private val accountsService: AptosAccountsService, - feeService: AptosFeeService, -) : NativeTransferPreloader, TokenTransferPreloader, SwapTransactionPreloader { - - private val feeCalculator = AptosFeeCalculator(chain, feeService) - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - return preloadTransfer(params) - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams { - return preloadTransfer(params) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - return preloadTransfer(params) - } - - private suspend fun preloadTransfer(params: ConfirmParams): SignerParams { - val sequence = try { - val response = accountsService.accounts(params.from.address).getOrThrow() - response.sequence_number?.toLong() ?: 0L - } catch (_: Throwable) { - 0L - } - val fee = feeCalculator.calculate(params, sequence) - val input = SignerParams(params, AptosChainData(sequence, fee)) - return input - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class AptosChainData( - val sequence: Long, - val fees: List, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fees.firstOrNull { it.priority == speed } ?: fees.first() - - override fun allFee(): List = fees - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosTransactionStatusClient.kt deleted file mode 100644 index 3de240ca2..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/AptosTransactionStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.aptos.services.AptosTransactionsService -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import java.math.BigInteger - -class AptosTransactionStatusClient( - private val chain: Chain, - private val rpcClient: AptosTransactionsService, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val transaction = rpcClient.transactions(request.hash).getOrNull() ?: throw ServiceUnavailable - - val status = if (transaction.success) TransactionState.Confirmed else TransactionState.Reverted - val fee = BigInteger(transaction.gas_used) * BigInteger(transaction.gas_unit_price) - return TransactionChanges(status, fee) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/models/AptosAccount.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/models/AptosAccount.kt deleted file mode 100644 index e452a2b1a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/models/AptosAccount.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.models - -import kotlinx.serialization.Serializable - -@Serializable -data class AptosAccount( - val sequence_number: String?, - val message: String?, - val error_code: String?, -) - -const val aptosErrorCode = "account_not_found" \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosAccountsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosAccountsService.kt deleted file mode 100644 index f29d5d56b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosAccountsService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.gemwallet.android.blockchain.clients.aptos.models.AptosAccount -import retrofit2.http.GET -import retrofit2.http.Path - -interface AptosAccountsService { - @GET("/v1/accounts/{address}") - suspend fun accounts(@Path("address") address: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosBalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosBalancesService.kt deleted file mode 100644 index 13d09c5b0..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosBalancesService.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.wallet.core.blockchain.aptos.AptosResource -import com.wallet.core.blockchain.aptos.AptosResourceBalanceOptional -import okhttp3.ResponseBody -import retrofit2.http.GET -import retrofit2.http.Path - -interface AptosBalancesService { - @GET("/v1/accounts/{address}/balance/{assetType}") - suspend fun balance(@Path("address") address: String, @Path("assetType") assetType: String): ResponseBody -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosBroadcastService.kt deleted file mode 100644 index fe936ad70..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosBroadcastService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.wallet.core.blockchain.aptos.AptosTransactionBroacast -import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.Headers -import retrofit2.http.POST - -interface AptosBroadcastService { - @Headers("Content-type: application/json") - @POST("/v1/transactions") - suspend fun broadcast(@Body request: RequestBody): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosFeeService.kt deleted file mode 100644 index 67b981baf..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosFeeService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.wallet.core.blockchain.aptos.AptosGasFee -import com.wallet.core.blockchain.aptos.AptosTransaction -import com.wallet.core.blockchain.aptos.AptosTransactionSimulation -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Headers -import retrofit2.http.POST - -interface AptosFeeService { - @GET("/v1/estimate_gas_price") - suspend fun feePrice(): Result - - @Headers("Content-type: application/json") - @POST("/v1/transactions/simulate?estimate_max_gas_amount=true") - suspend fun simulate(@Body data: AptosTransactionSimulation): Result> -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosNodeStatusService.kt deleted file mode 100644 index 11f0f319c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosNodeStatusService.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.wallet.core.blockchain.aptos.AptosLedger -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Url - -interface AptosNodeStatusService { - @GET - suspend fun ledger(@Url url: String): Response - - suspend fun AptosServices.getLedger(url: String): Response { - return ledger("$url/v1") - } -} - -suspend fun AptosNodeStatusService.getLedger(url: String): Response { - return ledger("$url/v1") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosServices.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosServices.kt deleted file mode 100644 index cce33bcce..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosServices.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -interface AptosServices : - AptosAccountsService, - AptosBalancesService, - AptosBroadcastService, - AptosFeeService, - AptosNodeStatusService, - AptosTransactionsService, - AptosTokensService \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosTokensService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosTokensService.kt deleted file mode 100644 index 29d3199cd..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosTokensService.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.wallet.core.blockchain.aptos.AptosCoinInfo -import com.wallet.core.blockchain.aptos.AptosResource -import retrofit2.http.GET -import retrofit2.http.Path - -interface AptosTokensService { - - @GET("/v1/accounts/{address}/resource/{resource}") - suspend fun resource(@Path("address") address: String, @Path("resource") resource: String): Result> -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosTransactionsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosTransactionsService.kt deleted file mode 100644 index 4a1ee5ae5..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/aptos/services/AptosTransactionsService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos.services - -import com.wallet.core.blockchain.aptos.AptosTransaction -import retrofit2.http.GET -import retrofit2.http.Path - -interface AptosTransactionsService { - @GET("/v1/transactions/by_hash/{id}") - suspend fun transactions(@Path("id") txId: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinBalanceClient.kt deleted file mode 100644 index f4a02d601..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinBalanceClient.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinBalancesService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.fullAddress -import com.gemwallet.android.ext.toBitcoinChain -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Chain - -class BitcoinBalanceClient( - private val chain: Chain, - private val balanceService: BitcoinBalancesService, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - val address = chain.toBitcoinChain().fullAddress(address) - val result = balanceService.balance(address).getOrNull() - return try { - AssetBalance.create(chain.asset(), available = result?.balance ?: return null) - } catch (_: Throwable) { - null - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinBroadcastClient.kt deleted file mode 100644 index 75eb9dcc5..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinBroadcastClient.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinBroadcastService -import com.gemwallet.android.blockchain.rpc.RpcError -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import okhttp3.RequestBody.Companion.toRequestBody - -class BitcoinBroadcastClient( - private val chain: Chain, - private val broadcastService: BitcoinBroadcastService, -) : BroadcastClient { - - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val requestBody = signedMessage.toHexString("").toRequestBody(Mime.Plain.value) - return broadcastService.broadcast(requestBody).getOrThrow().result - ?: throw RpcError.BroadcastFail("Unknown error") - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinChainData.kt new file mode 100644 index 000000000..aa6cf5ef0 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinChainData.kt @@ -0,0 +1,16 @@ +package com.gemwallet.android.blockchain.clients.bitcoin + +import com.gemwallet.android.blockchain.services.mapper.toUtxo +import com.gemwallet.android.model.ChainSignData +import com.wallet.core.primitives.UTXO +import uniffi.gemstone.GemTransactionLoadMetadata + +data class BitcoinChainData( + val utxo: List, +) : ChainSignData + +fun GemTransactionLoadMetadata.Bitcoin.toChainData(): BitcoinChainData { + return BitcoinChainData( + utxo = utxos.toUtxo() + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinFeeCalculator.kt deleted file mode 100644 index 78062299a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinFeeCalculator.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinFeeService -import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy -import com.gemwallet.android.ext.toBitcoinChain -import com.gemwallet.android.model.Crypto -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.GasFee -import com.wallet.core.blockchain.bitcoin.BitcoinUTXO -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.BitcoinChain -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.withContext -import uniffi.gemstone.Config -import wallet.core.java.AnySigner -import wallet.core.jni.BitcoinSigHashType -import wallet.core.jni.CoinTypeConfiguration -import wallet.core.jni.proto.Bitcoin -import wallet.core.jni.proto.Common -import java.math.BigDecimal -import java.math.BigInteger -import java.math.RoundingMode - -class BitcoinFeeCalculator( - private val feeService: BitcoinFeeService, -) { - suspend fun calculate( - utxos: List, - account: Account, - recipient: String, - amount: BigInteger, - ): List = withContext(Dispatchers.IO) { - val ownerAddress = account.address - val chain = account.chain - FeePriority.entries.map { - async { - val price = estimateFeePrice(chain, it) - val limit = - calcFee(chain, ownerAddress, recipient, amount.toLong(), price.toLong(), utxos) - GasFee( - feeAssetId = AssetId(chain), - priority = it, - maxGasPrice = price, - limit = limit - ) - } - }.awaitAll() - } - - private suspend fun estimateFeePrice(chain: Chain, speed: FeePriority): BigInteger { - val decimals = CoinTypeConfiguration.getDecimals(WCChainTypeProxy().invoke(chain)) - val minimumByteFee = getMinimumByteFee(chain) - val priority = Config().getBitcoinChainConfig(chain.toBitcoinChain().string).blocksFeePriority.let { - when (speed) { - FeePriority.Slow -> it.slow - FeePriority.Normal -> it.normal - FeePriority.Fast -> it.fast - } - }.toString() - return feeService.estimateFee(priority).fold( - { - val networkFeePerKb = Crypto(it.result, decimals).atomicValue - val feePerByte = networkFeePerKb.toBigDecimal().divide(BigDecimal(1000), RoundingMode.CEILING).toBigInteger() - return minimumByteFee.max(feePerByte) - } - ) { - minimumByteFee - } - } - - private fun calcFee( - chain: Chain, - from: String, - to: String, - amount: Long, - bytePrice: Long, - utxos: List, - ): BigInteger { - val coinType = WCChainTypeProxy().invoke(chain) - val total = utxos.map { it.value.toLong() }.fold(0L) { x, y -> x + y } - if (total == 0L) { - return BigInteger.ZERO // empty balance - } - val input = Bitcoin.SigningInput.newBuilder().apply { - this.hashType = BitcoinSigHashType.ALL.value() - this.byteFee = bytePrice - this.amount = amount - this.useMaxAmount = total == amount - this.coinType = coinType.value() - this.toAddress = to - this.changeAddress = from - this.addAllUtxo(utxos.getUtxoTransactions(from, coinType)) - }.build() - - val plan = AnySigner.plan(input, coinType, Bitcoin.TransactionPlan.parser()) - when (plan.error) { - Common.SigningError.OK -> { /* continue */ } - Common.SigningError.Error_not_enough_utxos, - Common.SigningError.Error_dust_amount_requested, - Common.SigningError.Error_missing_input_utxos -> throw IllegalStateException("Dust Error: $bytePrice") - else -> throw IllegalStateException(plan.error.name) - } - - val selectedUtxos: MutableList = mutableListOf() - for (raw in plan.utxosList) { - input.utxoList?.indexOfFirst { it == raw }?.let { - selectedUtxos.add(utxos[it]) - } - } - if (utxos.isNotEmpty() && selectedUtxos.isEmpty() && amount != total && amount <= total) { - return calcFee(chain, from, to, total, bytePrice, utxos) - } - return BigInteger.valueOf(plan.fee / bytePrice) - } - - companion object { - fun getMinimumByteFee(chain: Chain) = when (chain.toBitcoinChain()) { - BitcoinChain.Litecoin -> BigInteger("5") - BitcoinChain.Doge -> BigInteger("1000") - BitcoinChain.BitcoinCash, - BitcoinChain.Bitcoin -> BigInteger.ONE - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinGatewayEstimateFee.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinGatewayEstimateFee.kt new file mode 100644 index 000000000..e06168b5f --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinGatewayEstimateFee.kt @@ -0,0 +1,105 @@ +package com.gemwallet.android.blockchain.clients.bitcoin + +import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy +import com.gemwallet.android.blockchain.services.mapper.toUtxo +import com.gemwallet.android.ext.toChain +import com.wallet.core.primitives.UTXO +import uniffi.gemstone.Chain +import uniffi.gemstone.GemFeeOptions +import uniffi.gemstone.GemGasPriceType +import uniffi.gemstone.GemGatewayEstimateFee +import uniffi.gemstone.GemTransactionLoadFee +import uniffi.gemstone.GemTransactionLoadInput +import uniffi.gemstone.GemTransactionLoadMetadata +import wallet.core.java.AnySigner +import wallet.core.jni.BitcoinSigHashType +import wallet.core.jni.proto.Bitcoin +import wallet.core.jni.proto.Common +import java.math.BigInteger + +class BitcoinGatewayEstimateFee : GemGatewayEstimateFee { + override suspend fun getFee( + chain: Chain, + input: GemTransactionLoadInput + ): GemTransactionLoadFee? { + val chain = chain.toChain() ?: throw IllegalArgumentException("Incorrect chain") + + val utxos = (input.metadata as? GemTransactionLoadMetadata.Bitcoin)?.utxos?.toUtxo() + ?: throw IllegalArgumentException("Incorrect UTXO") + + val bytePrice = (input.gasPrice as? GemGasPriceType.Regular)?.gasPrice?.toLongOrNull() + ?: throw IllegalArgumentException("Incorrect Byte Price") + val amount = input.value.toLongOrNull() ?: return null + + val destinationAddress = input.destinationAddress + val senderAddress = input.senderAddress + + val fee = calcFee( + chain = chain, + senderAddress = senderAddress, + destinationAddress = destinationAddress, + amount = amount, + bytePrice = bytePrice, + utxos = utxos + ) + + return GemTransactionLoadFee( + fee = fee.toString(), + gasPriceType = input.gasPrice, + gasLimit = "1", + options = GemFeeOptions(emptyMap()) + ) + } + + override suspend fun getFeeData( + chain: Chain, + input: GemTransactionLoadInput + ): String? { + return null + } + + private fun calcFee( + chain: com.wallet.core.primitives.Chain, + senderAddress: String, + destinationAddress: String, + amount: Long, + bytePrice: Long, + utxos: List, + ): BigInteger { + val coinType = WCChainTypeProxy().invoke(chain) + val total = utxos.map { it.value.toLong() }.fold(0L) { x, y -> x + y } + if (total == 0L) { + return BigInteger.ZERO // empty balance + } + val input = Bitcoin.SigningInput.newBuilder().apply { + this.hashType = BitcoinSigHashType.ALL.value() + this.byteFee = bytePrice + this.amount = amount + this.useMaxAmount = total == amount + this.coinType = coinType.value() + this.toAddress = destinationAddress + this.changeAddress = senderAddress + this.addAllUtxo(utxos.getUtxoTransactions(senderAddress, coinType)) + }.build() + + val plan = AnySigner.plan(input, coinType, Bitcoin.TransactionPlan.parser()) + when (plan.error) { + Common.SigningError.OK -> { /* continue */ } + Common.SigningError.Error_not_enough_utxos, + Common.SigningError.Error_dust_amount_requested, + Common.SigningError.Error_missing_input_utxos -> throw IllegalStateException("Dust Error: $bytePrice") + else -> throw IllegalStateException(plan.error.name) + } + + val selectedUtxos: MutableList = mutableListOf() + for (raw in plan.utxosList) { + input.utxoList?.indexOfFirst { it == raw }?.let { + selectedUtxos.add(utxos[it]) + } + } + if (utxos.isNotEmpty() && selectedUtxos.isEmpty() && amount != total && amount <= total) { + return calcFee(chain, senderAddress, destinationAddress, total, bytePrice, utxos) + } + return BigInteger.valueOf(plan.fee/* / bytePrice*/) // + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinNodeStatusClient.kt deleted file mode 100644 index d329d8a1f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinNodeStatusClient.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinNodeStatusService -import com.gemwallet.android.blockchain.clients.bitcoin.services.getBlock -import com.gemwallet.android.blockchain.clients.bitcoin.services.getNodeInfo -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class BitcoinNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: BitcoinNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val nodeInfoJob = async { nodeStatusService.getNodeInfo(url).getOrNull() } - val chainIdJob = async { nodeStatusService.getBlock(url) } - val nodeInfo = nodeInfoJob.await() ?: return@withContext null - val chainId = chainIdJob.await() - - NodeStatus( - url = url, - chainId = chainId.body()?.previousBlockHash ?: return@withContext null, - blockNumber = nodeInfo.blockbook.bestHeight.toString(), - inSync = nodeInfo.blockbook.inSync, - latency = chainId.getLatency() - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignClient.kt index 416b53cd0..c95675836 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignClient.kt @@ -6,12 +6,12 @@ import com.gemwallet.android.math.decodeHex import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.gemwallet.android.model.GasFee import com.google.protobuf.ByteString -import com.wallet.core.blockchain.bitcoin.BitcoinUTXO import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import com.wallet.core.primitives.SwapProvider +import com.wallet.core.primitives.UTXO import wallet.core.java.AnySigner import wallet.core.jni.BitcoinScript import wallet.core.jni.CoinType @@ -29,14 +29,14 @@ class BitcoinSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val signingInput = getSigningInput( params, chainData, finalAmount, - feePriority, + fee, privateKey ) return sign(signingInput.build()) @@ -46,7 +46,7 @@ class BitcoinSignClient( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val providers = setOf(SwapProvider.Thorchain, SwapProvider.Chainflip) @@ -61,7 +61,7 @@ class BitcoinSignClient( params, chainData, finalAmount, - feePriority, + fee, privateKey, ) when(params.protocolId) { @@ -85,11 +85,11 @@ class BitcoinSignClient( params: ConfirmParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): Bitcoin.SigningInput.Builder { - val chainData = chainData as BitcoinSignerPreloader.BitcoinChainData - val gasFee = chainData.fee(feePriority) as GasFee + val chainData = chainData as BitcoinChainData + val gasFee = fee as GasFee val coinType = coinType return Bitcoin.SigningInput.newBuilder().apply { @@ -102,7 +102,7 @@ class BitcoinSignClient( this.useMaxAmount = params.isMax() this.addPrivateKey(ByteString.copyFrom(privateKey)) this.addAllUtxo(chainData.utxo.getUtxoTransactions(params.from.address, coinType)) - chainData.utxo.forEach { + chainData.utxo.forEach { _ -> val redeemScript = BitcoinScript.lockScriptForAddress(params.from.address, coinType) val scriptData = redeemScript.data() if (coinType == CoinType.BITCOIN || scriptData?.isNotEmpty() == true) { @@ -126,16 +126,16 @@ class BitcoinSignClient( if (output.errorMessage.isNotEmpty()) { throw IllegalStateException(output.errorMessage) } - return listOf(output.encoded.toByteArray()) + return listOf(output.encoded.toByteArray().toHexString("").toByteArray()) } override fun supported(chain: Chain): Boolean = this.chain == chain } -fun List.getUtxoTransactions(address: String, coinType: CoinType): List { +fun List.getUtxoTransactions(address: String, coinType: CoinType): List { return map { utxo -> Bitcoin.UnspentTransaction.newBuilder().apply { - val hash = utxo.txid.decodeHex() + val hash = utxo.transaction_id.decodeHex() hash.reverse() this.outPoint = Bitcoin.OutPoint.newBuilder().apply { this.hash = ByteString.copyFrom(hash) diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignerPreloader.kt deleted file mode 100644 index c3f14356c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinSignerPreloader.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinFeeService -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinUTXOService -import com.gemwallet.android.ext.fullAddress -import com.gemwallet.android.ext.toBitcoinChain -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.blockchain.bitcoin.BitcoinUTXO -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import java.math.BigInteger - -class BitcoinSignerPreloader( - private val chain: Chain, - private val utxoService: BitcoinUTXOService, - feeService: BitcoinFeeService, -) : NativeTransferPreloader, SwapTransactionPreloader { - - private val feeCalculator = BitcoinFeeCalculator(feeService) - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - val data = preload(params.from, params.destination().address, params.amount) - return SignerParams(params, data) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - val data = preload(params.from, params.destination().address, params.amount) - return SignerParams(params, data) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private suspend fun preload(fromAccount: Account, destinationAddress: String, amount: BigInteger): BitcoinChainData { - val address = chain.toBitcoinChain().fullAddress(fromAccount.address) - val utxo = utxoService.getUTXO(address).getOrNull() ?: throw Exception("Can't load UTXO") - val fee = feeCalculator.calculate(utxo, fromAccount, destinationAddress, amount) - return BitcoinChainData(utxo, fee) - } - - data class BitcoinChainData( - val utxo: List, - val fee: List, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee.firstOrNull { it.priority == speed } ?: fee.first() - - override fun allFee(): List = fee - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinTransactionStatusClient.kt deleted file mode 100644 index 7b249c976..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/BitcoinTransactionStatusClient.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinTransactionsService -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class BitcoinTransactionStatusClient( - private val chain: Chain, - private val rpcClient: BitcoinTransactionsService -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val tx = rpcClient.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - return TransactionChanges(if (tx.blockHeight > 0) TransactionState.Confirmed else TransactionState.Pending) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinBalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinBalancesService.kt deleted file mode 100644 index 420d69535..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinBalancesService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinAccount -import retrofit2.http.GET -import retrofit2.http.Path - -interface BitcoinBalancesService { - @GET("/api/v2/address/{address}") - suspend fun balance(@Path("address") address: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinBroadcastService.kt deleted file mode 100644 index 2bbe5af21..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinBroadcastService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinTransactionBroacastResult -import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.POST - -interface BitcoinBroadcastService { - @POST("/api/v2/sendtx/") - suspend fun broadcast(@Body body: RequestBody): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinFeeService.kt deleted file mode 100644 index 6bdf049ef..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinFeeService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinFeeResult -import retrofit2.http.GET -import retrofit2.http.Path - -interface BitcoinFeeService { - @GET("/api/v2/estimatefee/{priority}") - suspend fun estimateFee(@Path("priority") priority: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinNodeStatusService.kt deleted file mode 100644 index ac26fc3a3..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinNodeStatusService.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinBlock -import com.wallet.core.blockchain.bitcoin.BitcoinNodeInfo -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Url - -interface BitcoinNodeStatusService { - @GET//("/api/v2/") - suspend fun nodeInfo(@Url url: String): Result - - @GET//("/api/v2/block/{block}") - suspend fun block(@Url url: String): Response -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinRpcClient.kt deleted file mode 100644 index 6b790990b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinRpcClient.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinBlock -import com.wallet.core.blockchain.bitcoin.BitcoinNodeInfo -import retrofit2.Response - -interface BitcoinRpcClient : - BitcoinBalancesService, - BitcoinUTXOService, - BitcoinFeeService, - BitcoinBroadcastService, - BitcoinTransactionsService, - BitcoinNodeStatusService - -suspend fun BitcoinNodeStatusService.getBlock(url: String): Response { - return block("$url/api/v2/block/1") -} - -suspend fun BitcoinNodeStatusService.getNodeInfo(url: String): Result { - return nodeInfo("$url/api/v2") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinTransactionsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinTransactionsService.kt deleted file mode 100644 index 14a18b601..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinTransactionsService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinTransaction -import retrofit2.http.GET -import retrofit2.http.Path - -interface BitcoinTransactionsService { - @GET("/api/v2/tx/{txId}") - suspend fun transaction(@Path("txId") txId: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinUTXOService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinUTXOService.kt deleted file mode 100644 index b11ad9f60..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/services/BitcoinUTXOService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin.services - -import com.wallet.core.blockchain.bitcoin.BitcoinUTXO -import retrofit2.http.GET -import retrofit2.http.Path - -interface BitcoinUTXOService { - @GET("/api/v2/utxo/{address}") - suspend fun getUTXO(@Path("address") address: String): Result> -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoBalanceClient.kt deleted file mode 100644 index 536afbbd4..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoBalanceClient.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.cardano.services.CardanoBalanceService -import com.gemwallet.android.blockchain.clients.cardano.services.balance -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Chain - -class CardanoBalanceClient( - private val chain: Chain, - private val balanceService: CardanoBalanceService, -) : BalanceClient { - - override suspend fun getNativeBalance( - chain: Chain, - address: String - ): AssetBalance? { - val amount = try { - balanceService.balance(address) - } catch (_: Throwable) { - null - } ?: return null - return AssetBalance.create(chain.asset(), available = amount.toString()) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoBroadcastClient.kt deleted file mode 100644 index a147bd71c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoBroadcastClient.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.cardano.services.CardanoBroadcastService -import com.gemwallet.android.blockchain.clients.cardano.services.broadcast -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class CardanoBroadcastClient( - private val chain: Chain, - private val broadcastService: CardanoBroadcastService -) : BroadcastClient { - override suspend fun send( - account: Account, - signedMessage: ByteArray, - type: TransactionType - ): String { - return broadcastService.broadcast(signedMessage.toHexString(prefix = ""))?.submitTransaction?.hash - ?: throw ServiceError.EmptyHash - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoChainData.kt new file mode 100644 index 000000000..55f8e369d --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoChainData.kt @@ -0,0 +1,16 @@ +package com.gemwallet.android.blockchain.clients.cardano + +import com.gemwallet.android.blockchain.services.mapper.toUtxo +import com.gemwallet.android.model.ChainSignData +import com.wallet.core.primitives.UTXO +import uniffi.gemstone.GemTransactionLoadMetadata + +data class CardanoChainData( + val utxos: List, +) : ChainSignData + +fun GemTransactionLoadMetadata.Cardano.toChainData(): CardanoChainData { + return CardanoChainData( + utxos = utxos.toUtxo(), + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoGatewayEstimateFee.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoGatewayEstimateFee.kt new file mode 100644 index 000000000..9a783da93 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoGatewayEstimateFee.kt @@ -0,0 +1,83 @@ +package com.gemwallet.android.blockchain.clients.cardano + +import com.gemwallet.android.blockchain.services.mapper.toUtxo +import com.gemwallet.android.math.decodeHex +import com.google.protobuf.ByteString +import com.wallet.core.primitives.UTXO +import uniffi.gemstone.Chain +import uniffi.gemstone.GemFeeOptions +import uniffi.gemstone.GemGatewayEstimateFee +import uniffi.gemstone.GemTransactionLoadFee +import uniffi.gemstone.GemTransactionLoadInput +import uniffi.gemstone.GemTransactionLoadMetadata +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Cardano +import java.math.BigInteger + +class CardanoGatewayEstimateFee : GemGatewayEstimateFee { + override suspend fun getFee( + chain: Chain, + input: GemTransactionLoadInput + ): GemTransactionLoadFee? { + val utxos = (input.metadata as? GemTransactionLoadMetadata.Cardano)?.utxos?.toUtxo() + ?: throw IllegalArgumentException("Incorrect UTXO") + + val amount = input.value.toLongOrNull() ?: return null + + val destination = input.destinationAddress + val from = input.senderAddress + + val fee = calcFee( + from = from, + to = destination, amount, + useMaxAmount = input.isMaxValue, + utxos + ) + + return GemTransactionLoadFee( + fee = fee.toString(), + gasPriceType = input.gasPrice, + gasLimit = "1", + options = GemFeeOptions(emptyMap()) + ) + } + + override suspend fun getFeeData( + chain: Chain, + input: GemTransactionLoadInput + ): String? { + return null + } + + private fun calcFee( + from: String, + to: String, + amount: Long, + useMaxAmount: Boolean, + utxos: List, + ): BigInteger { + val signingInput = Cardano.SigningInput.newBuilder().apply { + this.addAllUtxos( + utxos.map { utxo -> + Cardano.TxInput.newBuilder().apply { + this.address = utxo.address + this.amount = utxo.value.toLong() + this.outPoint = Cardano.OutPoint.newBuilder().apply { + this.txHash = ByteString.copyFrom(utxo.transaction_id.decodeHex()) + this.outputIndex = utxo.vout.toLong() + }.build() + }.build() + } + ) + this.transferMessage = Cardano.Transfer.newBuilder().apply { + this.toAddress = to + this.changeAddress = from + this.amount = amount + this.useMaxAmount = useMaxAmount + }.build() + }.build() + val plan: Cardano.TransactionPlan = AnySigner.plan(signingInput, CoinType.CARDANO, Cardano.TransactionPlan.parser()) + return plan.fee.toBigInteger() + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoNodeStatusClient.kt deleted file mode 100644 index 4daa5a0fb..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoNodeStatusClient.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.cardano.services.CardanoNodeStatusService -import com.gemwallet.android.blockchain.clients.cardano.services.latestBlock -import com.gemwallet.android.blockchain.clients.cardano.services.networkMagic -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class CardanoNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: CardanoNodeStatusService -) : NodeStatusClient { - - override suspend fun getNodeStatus( - chain: Chain, - url: String - ): NodeStatus? = withContext(Dispatchers.IO) { - val getLatestBlock = async { nodeStatusService.latestBlock(url) } - val getNetworkMagic = async { nodeStatusService.networkMagic(url) } - val latestBlock = getLatestBlock.await() - val networkMagic = getNetworkMagic.await() - NodeStatus( - url = url, - chainId = networkMagic.body()?.data?.genesis?.shelley?.networkMagic?.toString() ?: "-", - blockNumber = latestBlock.body()?.data?.cardano?.tip?.number?.toString() ?: return@withContext null, - inSync = true, - latency = latestBlock.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignClient.kt index 9ee08b2cc..4fe8223e0 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignClient.kt @@ -2,11 +2,12 @@ package com.gemwallet.android.blockchain.clients.cardano import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.math.decodeHex +import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.java.AnySigner import wallet.core.jni.CoinType import wallet.core.jni.proto.Cardano @@ -20,10 +21,10 @@ class CardanoSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = (chainData as? CardanoSignerPreloaderClient.CardanoChainData) + val chainData = (chainData as? CardanoChainData) ?: throw IllegalArgumentException() val signingInput = Cardano.SigningInput.newBuilder().apply { this.addPrivateKey(ByteString.copyFrom(privateKey)) @@ -51,7 +52,7 @@ class CardanoSignClient( if (!output.errorMessage.isNullOrEmpty()) { throw Exception(output.errorMessage) } - return listOf(output.encoded.toByteArray()) + return listOf(output.encoded.toByteArray().toHexString("").toByteArray()) } override fun supported(chain: Chain): Boolean = this.chain == chain diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignerPreloaderClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignerPreloaderClient.kt deleted file mode 100644 index 6b1011198..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoSignerPreloaderClient.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.cardano.services.CardanoServices -import com.gemwallet.android.blockchain.clients.cardano.services.utxos -import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.google.protobuf.ByteString -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import com.wallet.core.primitives.UTXO -import wallet.core.java.AnySigner -import wallet.core.jni.CoinType -import wallet.core.jni.proto.Cardano - -class CardanoSignerPreloaderClient( - private val chain: Chain, - private val feeServices: CardanoServices -) : NativeTransferPreloader { - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - val utxos = feeServices.utxos(params.from.address) - val fee = calculateFee(params, utxos) - - return SignerParams( - input = params, - chainData = CardanoChainData( - fee = Fee( - feeAssetId = AssetId(chain), - priority = FeePriority.Normal, - amount = fee.toBigInteger(), - ), - utxos = utxos, - ) - ) - } - - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private fun calculateFee(params: ConfirmParams.TransferParams.Native, utxos: List): Long { - val signingInput = Cardano.SigningInput.newBuilder().apply { - this.addAllUtxos( - utxos.map { utxo -> - Cardano.TxInput.newBuilder().apply { - this.address = utxo.address - this.amount = utxo.value.toLong() - this.outPoint = Cardano.OutPoint.newBuilder().apply { - this.txHash = ByteString.copyFrom(utxo.transaction_id.decodeHex()) - this.outputIndex = utxo.vout.toLong() - }.build() - }.build() - } - ) - this.transferMessage = Cardano.Transfer.newBuilder().apply { - this.toAddress = params.destination.address - this.changeAddress = params.from.address - this.amount = params.amount.toLong() - this.useMaxAmount = params.isMaxAmount - }.build() - }.build() - val plan: Cardano.TransactionPlan = AnySigner.plan(signingInput, CoinType.CARDANO, Cardano.TransactionPlan.parser()) - return plan.fee - } - - data class CardanoChainData( - val fee: Fee, - val utxos: List, - ) : ChainSignData { - - override fun fee(speed: FeePriority): Fee = fee - - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoTransactionStatusClient.kt deleted file mode 100644 index 763f0b90a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/CardanoTransactionStatusClient.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.cardano.services.CardanoTransactionService -import com.gemwallet.android.blockchain.clients.cardano.services.transaction -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class CardanoTransactionStatusClient( - private val chain: Chain, - private val transactionsService: CardanoTransactionService, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val transaction = transactionsService.transaction(request.hash) ?: throw ServiceUnavailable - return TransactionChanges( - state = TransactionState.Confirmed, - fee = transaction.fee.toBigInteger(), - ) -// TODO: transaction.block.number - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoBalanceService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoBalanceService.kt deleted file mode 100644 index 01e463f72..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoBalanceService.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano.services - -import com.wallet.core.blockchain.cardano.CardanoAggregateBalance -import com.wallet.core.blockchain.cardano.CardanoUTXOS -import com.wallet.core.primitives.GraphqlData -import com.wallet.core.primitives.GraphqlRequest -import retrofit2.http.Body -import retrofit2.http.POST -import java.math.BigInteger - -interface CardanoBalanceService { - - @POST("/") - suspend fun balance(@Body request: GraphqlRequest): Result>> - -} - -suspend fun CardanoBalanceService.balance(address: String): BigInteger? { - val request = GraphqlRequest( - operationName = "GetBalance", - variables = hashMapOf( - "address" to address - ), - query = "query GetBalance(\$address: String!) { utxos: utxos_aggregate(where: { address: { _eq: \$address } } ) { aggregate { sum { value } } } }" - ) - return balance(request).getOrNull()?.data?.utxos?.aggregate?.sum?.value?.toBigInteger() -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoBroadcastService.kt deleted file mode 100644 index 13910ef06..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoBroadcastService.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano.services - -import com.wallet.core.blockchain.cardano.CardanoTransactionBroadcast -import com.wallet.core.primitives.GraphqlData -import com.wallet.core.primitives.GraphqlRequest -import retrofit2.http.Body -import retrofit2.http.POST - -interface CardanoBroadcastService { - @POST("/") - suspend fun broadcast(@Body request: GraphqlRequest): Result> -} - -suspend fun CardanoBroadcastService.broadcast(data: String): CardanoTransactionBroadcast? { - val request = GraphqlRequest( - operationName = "SubmitTransaction", - variables = hashMapOf("transaction" to data), - query = "mutation SubmitTransaction(\$transaction: String!) { submitTransaction(transaction: \$transaction) { hash } }" - ) - val result = broadcast(request) - val data = result.getOrNull() - return data?.errors?.firstOrNull()?.let { - throw Exception(it.message) - } ?: data?.data -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoFeeService.kt deleted file mode 100644 index c051c380f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoFeeService.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano.services - -import com.wallet.core.blockchain.cardano.CardanoUTXO -import com.wallet.core.blockchain.cardano.CardanoUTXOS -import com.wallet.core.primitives.GraphqlData -import com.wallet.core.primitives.GraphqlRequest -import com.wallet.core.primitives.UTXO -import retrofit2.http.Body -import retrofit2.http.POST - -interface CardanoFeeService { - @POST("/") - suspend fun utxos(@Body request: GraphqlRequest): Result>>> -} - -suspend fun CardanoFeeService.utxos(address: String): List { - val request = GraphqlRequest( - operationName = "UtxoSetForAddress", - variables = hashMapOf("address" to address), - query = "query UtxoSetForAddress(\$address: String!) { utxos(order_by: { value: desc } , where: { address: { _eq: \$address } } ) { address value txHash index tokens { quantity asset { fingerprint policyId assetName } } } }" - ) - return utxos(request).getOrNull()?.data?.utxos?.map { - UTXO( - transaction_id = it.txHash, - vout = it.index, - value = it.value, - address = it.address, - ) - } ?: emptyList() -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoNodeStatusService.kt deleted file mode 100644 index c12d04581..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoNodeStatusService.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano.services - -import com.wallet.core.blockchain.cardano.CardanoBlockData -import com.wallet.core.blockchain.cardano.CardanoGenesisData -import com.wallet.core.primitives.GraphqlData -import com.wallet.core.primitives.GraphqlRequest -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST -import retrofit2.http.Url - -interface CardanoNodeStatusService { - @POST - suspend fun latestBlock(@Url url: String, @Body request: GraphqlRequest): Response> - - @POST - suspend fun networkMagic(@Url url: String, @Body request: GraphqlRequest): Response> -} - -suspend fun CardanoNodeStatusService.latestBlock(url: String): Response> { - val request = GraphqlRequest( - operationName = "GetBlockNumber", - variables = hashMapOf(), - query = "query GetBlockNumber { cardano { tip { number } } }" - ) - return latestBlock(url, request) -} - -suspend fun CardanoNodeStatusService.networkMagic(url: String): Response> { - val request = GraphqlRequest( - operationName = "GetNetworkMagic", - variables = hashMapOf(), - query = "query GetNetworkMagic { genesis { shelley { networkMagic } } }" - ) - return networkMagic(url, request) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoServices.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoServices.kt deleted file mode 100644 index 78be5b297..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoServices.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano.services - -interface CardanoServices : CardanoBalanceService, - CardanoTransactionService, - CardanoFeeService, - CardanoBroadcastService, - CardanoNodeStatusService \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoTransactionService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoTransactionService.kt deleted file mode 100644 index 34cf13111..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cardano/services/CardanoTransactionService.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cardano.services - -import com.wallet.core.blockchain.cardano.CardanoTransaction -import com.wallet.core.blockchain.cardano.CardanoTransactions -import com.wallet.core.primitives.GraphqlData -import com.wallet.core.primitives.GraphqlRequest -import retrofit2.http.Body -import retrofit2.http.POST - -interface CardanoTransactionService { - - @POST("/") - suspend fun transaction(@Body request: GraphqlRequest): Result> -} - -suspend fun CardanoTransactionService.transaction(hash: String): CardanoTransaction? { - val request = GraphqlRequest( - operationName = "TransactionsByHash", - variables = hashMapOf( - "hash" to hash, - ), - query = "query TransactionsByHash(\$hash: Hash32Hex!) { transactions(where: { hash: { _eq: \$hash } } ) { block { number } fee } }" - ) - return transaction(request).getOrNull()?.data?.transactions?.firstOrNull() -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosBalanceClient.kt deleted file mode 100644 index b17f873d8..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosBalanceClient.kt +++ /dev/null @@ -1,135 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosBalancesService -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosStakeService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.CosmosDenom -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class CosmosBalanceClient( - private val chain: Chain, - private val balancesService: CosmosBalancesService, - private val stakeService: CosmosStakeService, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? = withContext(Dispatchers.IO) { - val denom = CosmosDenom.from(chain) - - val getBalances = async { balancesService.getBalance(address).getOrNull()?.balances } - val response = getBalances.await() - val balance = response?.filter { it.denom == denom } - ?.map { it.amount.toBigDecimal().toBigInteger() } - ?.fold(BigInteger.ZERO) { acc, value -> acc + value} ?: return@withContext null - - when (chain) { - Chain.Thorchain, - Chain.Noble -> AssetBalance.create(chain.asset(), available = balance.toString()) - else -> { - val getDelegations = async { stakeService.delegations(address).getOrNull()?.delegation_responses } - val getUnboundingDelegations = async { stakeService.undelegations(address).getOrNull()?.unbonding_responses } - val getRewards = async { stakeService.rewards(address).getOrNull()?.rewards } - - val delegations = getDelegations.await() - ?.filter { it.balance.denom == denom } - ?.map { it.balance.amount.toBigDecimal().toBigInteger() } - ?.fold(BigInteger.ZERO) { acc, value -> acc + value} ?: return@withContext null - val undelegations = getUnboundingDelegations.await() - ?.mapNotNull { entry -> - entry.entries.map { it.balance.toBigDecimal().toBigInteger() } - .reduceOrNull { acc, value -> acc + value } - } - ?.fold(BigInteger.ZERO) { acc, value -> acc + value } ?: return@withContext null - val rewards = getRewards.await() - ?.mapNotNull { reward -> - reward.reward - .filter { it.denom == denom } - .map { it.amount.toBigDecimal().toBigInteger() } - .reduceOrNull { acc, value -> acc + value} - }?.fold(BigInteger.ZERO) { acc, value -> acc + value } ?: return@withContext null - AssetBalance.create( - asset = chain.asset(), - available = balance.toString(), - staked = delegations.toString(), - pending = undelegations.toString(), - rewards = rewards.toString(), - ) - } - } - } - - override suspend fun getDelegationBalances(chain: Chain, address: String): AssetBalance? = withContext(Dispatchers.IO) { - when (chain) { - Chain.Thorchain, - Chain.Noble -> return@withContext null - else -> {} - } - val denom = CosmosDenom.from(chain) - - val getDelegations = async { stakeService.delegations(address).getOrNull()?.delegation_responses } - val getUnboundingDelegations = async { stakeService.undelegations(address).getOrNull()?.unbonding_responses } - val getRewards = async { stakeService.rewards(address).getOrNull()?.rewards } - - val delegations = getDelegations.await() - ?.filter { it.balance.denom == denom } - ?.map { it.balance.amount.toBigDecimal().toBigInteger() } - ?.fold(BigInteger.ZERO) { acc, value -> acc + value} ?: return@withContext null - val undelegations = getUnboundingDelegations.await() - ?.mapNotNull { entry -> - entry.entries.map { it.balance.toBigDecimal().toBigInteger() } - .reduceOrNull { acc, value -> acc + value } - } - ?.fold(BigInteger.ZERO) { acc, value -> acc + value } ?: return@withContext null - val rewards = getRewards.await() - ?.mapNotNull { reward -> - reward.reward - .filter { it.denom == denom } - .map { it.amount.toBigDecimal().toBigInteger() } - .reduceOrNull { acc, value -> acc + value} - }?.fold(BigInteger.ZERO) { acc, value -> acc + value } ?: return@withContext null - AssetBalance.create( - asset = chain.asset(), - staked = delegations.toString(), - pending = undelegations.toString(), - rewards = rewards.toString(), - ) - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - val balances = try { - balancesService.getBalance(address).getOrNull() ?: return emptyList() - } catch (_: Throwable) { - return emptyList() - } - return tokens.map { asset -> - val amount = balances.balances.firstOrNull { it.denom == asset.id.tokenId }?.amount ?: "0" - AssetBalance.create( - asset, - available = try { - amount - } catch (_: Throwable) { - return@map null - } - ) - }.mapNotNull { it } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} - -fun CosmosDenom.Companion.from(chain: Chain): String = when (chain) { - Chain.Cosmos -> CosmosDenom.Uatom.string - Chain.Osmosis -> CosmosDenom.Uosmo.string - Chain.Thorchain -> CosmosDenom.Rune.string - Chain.Celestia -> CosmosDenom.Utia.string - Chain.Injective -> CosmosDenom.Inj.string - Chain.Sei -> CosmosDenom.Usei.string - Chain.Noble -> CosmosDenom.Uusdc.string - else -> throw IllegalArgumentException("Coin is not supported") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosBroadcastClient.kt deleted file mode 100644 index 757a39f70..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosBroadcastClient.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosBroadcastService -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import okhttp3.RequestBody.Companion.toRequestBody - -class CosmosBroadcastClient( - private val chain: Chain, - private val broadcastService: CosmosBroadcastService, -) : BroadcastClient { - - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val requestData = signedMessage.toString(Charsets.UTF_8) - val requestBody = requestData.toRequestBody(Mime.Json.value) - val result = broadcastService.broadcast(requestBody) - val data = result.getOrNull() ?: throw Exception(result.exceptionOrNull()?.message ?: "Broadcast error") - if (data.tx_response.code != 0) { - throw Exception(data.tx_response.raw_log) - } - return data.tx_response.txhash - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosChainData.kt new file mode 100644 index 000000000..4eb3c3e83 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosChainData.kt @@ -0,0 +1,18 @@ +package com.gemwallet.android.blockchain.clients.cosmos + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class CosmosChainData( + val chainId: String, + val accountNumber: ULong, + val sequence: ULong, +) : ChainSignData + +fun GemTransactionLoadMetadata.Cosmos.toChainData(): CosmosChainData { + return CosmosChainData( + chainId = chainId, + accountNumber = accountNumber, + sequence = sequence + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosDenom.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosDenom.kt new file mode 100644 index 000000000..f9e22173c --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosDenom.kt @@ -0,0 +1,15 @@ +package com.gemwallet.android.blockchain.clients.cosmos + +import com.wallet.core.primitives.Chain +import com.wallet.core.primitives.CosmosDenom + +fun CosmosDenom.Companion.from(chain: Chain): String = when (chain) { + Chain.Cosmos -> CosmosDenom.Uatom.string + Chain.Osmosis -> CosmosDenom.Uosmo.string + Chain.Thorchain -> CosmosDenom.Rune.string + Chain.Celestia -> CosmosDenom.Utia.string + Chain.Injective -> CosmosDenom.Inj.string + Chain.Sei -> CosmosDenom.Usei.string + Chain.Noble -> CosmosDenom.Uusdc.string + else -> throw IllegalArgumentException("Coin is not supported") +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosFeeCalculator.kt deleted file mode 100644 index a544a6a93..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosFeeCalculator.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.GasFee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import com.wallet.core.primitives.TransactionType -import java.math.BigInteger - -class CosmosFeeCalculator( - private val chain: Chain, -) { - fun calculate(txType: TransactionType): Fee { - val assetId = AssetId(chain) - val maxGasFee = when (chain) { - Chain.Cosmos -> when (txType) { - TransactionType.Transfer, TransactionType.Swap -> BigInteger.valueOf(3_000L) - else -> BigInteger.valueOf(25_000L) - } - Chain.Osmosis -> when (txType) { - TransactionType.Transfer, TransactionType.Swap -> BigInteger.valueOf(10_000L) - else -> BigInteger.valueOf(100_000L) - } - - Chain.Thorchain -> BigInteger.valueOf(2_000_000) - Chain.Celestia -> when (txType){ - TransactionType.Transfer, TransactionType.Swap -> BigInteger.valueOf(3_000L) - else -> BigInteger.valueOf(10_000L) - } - Chain.Injective -> when (txType){ - TransactionType.Transfer, TransactionType.Swap -> BigInteger.valueOf(100_000_000_000_000L) - else -> BigInteger.valueOf(1_000_000_000_000_000L) - } - Chain.Sei -> when (txType){ - TransactionType.Transfer, TransactionType.Swap -> BigInteger.valueOf(100_000L) - else -> BigInteger.valueOf(200_000L) - } - Chain.Noble -> BigInteger.valueOf(25_000) - else -> throw IllegalArgumentException("Unsupported chain") - } - val limit = when (txType) { - TransactionType.Transfer, TransactionType.Swap -> BigInteger.valueOf(200_000L) - TransactionType.StakeDelegate, - TransactionType.StakeUndelegate -> BigInteger.valueOf(1_000_000) - TransactionType.StakeRewards -> BigInteger.valueOf(900_000) - TransactionType.StakeRedelegate -> BigInteger.valueOf(1_250_000) - TransactionType.StakeWithdraw, - TransactionType.AssetActivation, - TransactionType.TransferNFT, - TransactionType.SmartContractCall, - TransactionType.TokenApproval -> throw IllegalArgumentException("Chain not available: no limit fee") - - } - return GasFee( - feeAssetId = assetId, - priority = FeePriority.Normal, - maxGasPrice = maxGasFee, - amount = maxGasFee, - limit = limit, - ) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosNodeStatusClient.kt deleted file mode 100644 index 1c3e55fd2..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosNodeStatusClient.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosNodeStatusService -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class CosmosNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: CosmosNodeStatusService, -) : NodeStatusClient { - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val inSyncJob = async { nodeStatusService.syncing("$url/cosmos/base/tendermint/v1beta1/syncing") } - val nodeInfoJob = async { nodeStatusService.getNodeInfo("$url/cosmos/base/tendermint/v1beta1/blocks/latest").getOrNull()?.block?.header } - - val inSync = inSyncJob.await() - val nodeInfo = nodeInfoJob.await() ?: return@withContext null - - NodeStatus( - url = url, - inSync = !(inSync.body()?.syncing ?: return@withContext null), - blockNumber = nodeInfo.height, - chainId = nodeInfo.chain_id, - latency = inSync.getLatency() - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignClient.kt index 48eed6d79..d52c7f49d 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignClient.kt @@ -4,11 +4,12 @@ import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.gemwallet.android.model.GasFee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain import com.wallet.core.primitives.CosmosDenom -import com.wallet.core.primitives.FeePriority +import com.wallet.core.primitives.DelegationValidator import wallet.core.java.AnySigner import wallet.core.jni.AnyAddress import wallet.core.jni.CoinType @@ -30,7 +31,7 @@ class CosmosSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val denom = CosmosDenom.from(chain) @@ -40,7 +41,7 @@ class CosmosSignClient( coin = coin, amount = getAmount(finalAmount, denom = denom) ) - return sign(chainData, message, params.memo() ?: "", privateKey) + return sign(chainData, fee, message, params.memo() ?: "", privateKey) } @@ -48,7 +49,7 @@ class CosmosSignClient( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val denom = params.asset.id.tokenId!! @@ -59,14 +60,14 @@ class CosmosSignClient( coin = coin, amount = getAmount(finalAmount, denom = denom) ) - return sign(chainData, message, params.memo() ?: "", privateKey) + return sign(chainData, fee, message, params.memo() ?: "", privateKey) } override suspend fun signSwap( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val denom = CosmosDenom.from(chain) @@ -80,14 +81,14 @@ class CosmosSignClient( ) } val memo = params.swapData ?: throw IllegalArgumentException("No swap data") - return sign(chainData, message, memo, privateKey) + return sign(chainData, fee, message, memo, privateKey) } override suspend fun signTokenApproval( params: ConfirmParams.TokenApprovalParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { throw IllegalArgumentException() @@ -97,59 +98,59 @@ class CosmosSignClient( params: ConfirmParams.Stake.DelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val denom = CosmosDenom.from(chain) - val message = getStakeMessage(params.from.address, params.validatorId, getAmount(finalAmount, denom)) - return sign(chainData, message, "Stake via Gem Wallet", privateKey) + val message = getStakeMessage(params.from.address, params.validator.id, getAmount(finalAmount, denom)) + return sign(chainData, fee, message, "Stake via Gem Wallet", privateKey) } override suspend fun signRedelegate( params: ConfirmParams.Stake.RedelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val denom = CosmosDenom.from(chain) val message = getRedelegateMessage( delegatorAddress = params.from.address, - validatorSrcAddress = params.srcValidatorId, - validatorDstAddress = params.dstValidatorId, + validatorSrcAddress = params.delegation.validator.id, + validatorDstAddress = params.dstValidator.id, amount = getAmount(params.amount, denom), ) - return sign(chainData, message, "Stake via Gem Wallet", privateKey) + return sign(chainData, fee, message, "Stake via Gem Wallet", privateKey) } override suspend fun signRewards( params: ConfirmParams.Stake.RewardsParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val message = getRewardsMessage(params.from.address, params.validatorsId) - return sign(chainData, message, "Stake via Gem Wallet", privateKey) + val message = getRewardsMessage(params.from.address, params.validators) + return sign(chainData, fee, message, "Stake via Gem Wallet", privateKey) } override suspend fun signUndelegate( params: ConfirmParams.Stake.UndelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val denom = CosmosDenom.from(chain) - val message = getUnstakeMessage(params.from.address, params.validatorId, getAmount(params.amount, denom)) - return sign(chainData, message, "Stake via Gem Wallet", privateKey) + val message = getUnstakeMessage(params.from.address, params.delegation.validator.id, getAmount(params.amount, denom)) + return sign(chainData, fee, message, "Stake via Gem Wallet", privateKey) } override suspend fun signWithdraw( params: ConfirmParams.Stake.WithdrawParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { throw IllegalArgumentException() @@ -220,12 +221,12 @@ class CosmosSignClient( return listOf(message) } - fun getRewardsMessage(delegatorAddress: String, validators: List): List { + fun getRewardsMessage(delegatorAddress: String, validators: List): List { return validators.map { validator -> Message.newBuilder().apply { withdrawStakeRewardMessage = WithdrawDelegationReward.newBuilder().apply { this.delegatorAddress = delegatorAddress - this.validatorAddress = validator + this.validatorAddress = validator.id }.build() }.build() } @@ -268,12 +269,13 @@ class CosmosSignClient( private fun sign( chainData: ChainSignData, + fee: Fee, messages: List, memo: String, privateKey: ByteArray ): List { - val meta = chainData as CosmosSignerPreloader.CosmosChainData - val fee = meta.fee() as GasFee + val meta = chainData as CosmosChainData + val fee = fee as GasFee val feeAmount = fee.amount val gas = fee.limit.toLong() * messages.size val coin = WCChainTypeProxy().invoke(chain) @@ -295,8 +297,8 @@ class CosmosSignClient( this.mode = Cosmos.BroadcastMode.SYNC this.signingMode = Cosmos.SigningMode.Protobuf this.chainId = meta.chainId - this.accountNumber = meta.accountNumber - this.sequence = meta.sequence + this.accountNumber = meta.accountNumber.toLong() + this.sequence = meta.sequence.toLong() this.fee = cosmosFee this.memo = memo this.privateKey = ByteString.copyFrom(privateKey) diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignerPreloader.kt deleted file mode 100644 index 030bd6a0f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosSignerPreloader.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosAccountsService -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class CosmosSignerPreloader( - private val chain: Chain, - private val accountsService: CosmosAccountsService, -) : NativeTransferPreloader, TokenTransferPreloader, StakeTransactionPreloader, SwapTransactionPreloader { - - private val feeCalculator = CosmosFeeCalculator(chain) - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams { - return preload(params) - } - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - return preload(params) - } - override suspend fun preloadStake(params: ConfirmParams.Stake): SignerParams { - return preload(params) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - return preload(params) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private suspend fun preload(params: ConfirmParams) = withContext(Dispatchers.IO) { - val accountJob = async { - when (chain) { - Chain.Injective -> accountsService.getInjectiveAccountData(params.from.address).getOrNull()?.account?.base_account - else -> accountsService.getAccountData(params.from.address).getOrNull()?.account - } - } - val nodeInfoJob = async { accountsService.getNodeInfo().getOrNull()?.block?.header?.chain_id } - val fee = feeCalculator.calculate(params.getTxType()) - - val (account, nodeInfo) = Pair( - accountJob.await() ?: throw Exception("Can't get data (account) for sign"), - nodeInfoJob.await() ?: throw Exception("Can't get data (node info) for sign") - ) - SignerParams( - input = params, - chainData = CosmosChainData( - chainId = nodeInfo, - accountNumber = account.account_number.toLong(), - sequence = account.sequence.toLong(), - fee = fee, - ) - ) - } - - data class CosmosChainData( - val chainId: String, - val accountNumber: Long, - val sequence: Long, - val fee: Fee, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosStakeClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosStakeClient.kt deleted file mode 100644 index c13647cd1..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosStakeClient.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import android.annotation.SuppressLint -import com.gemwallet.android.blockchain.clients.StakeClient -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosStakeService -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.CosmosDenom -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationState -import com.wallet.core.primitives.DelegationValidator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import java.math.BigInteger -import java.text.SimpleDateFormat - -class CosmosStakeClient( - private val chain: Chain, - private val stakeService: CosmosStakeService, -) : StakeClient { - - @SuppressLint("SimpleDateFormat") - private val completionDateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX") - - override suspend fun getValidators(chain: Chain, apr: Double): List { - return stakeService.validators().getOrNull()?.validators?.map { - val commission = it.commission.commission_rates.rate.toDouble() - val isActive = !it.jailed && it.status == "BOND_STATUS_BONDED" - DelegationValidator( - chain = chain, - id = it.operator_address, - name = it.description.moniker, - isActive = isActive, - commision = commission, - apr = if (isActive) apr - (apr * commission) else 0.0, - ) - } ?: emptyList() - } - - override suspend fun getStakeDelegations(chain: Chain, address: String, apr: Double): List = withContext(Dispatchers.IO) { - val getDelegations = async { stakeService.delegations(address).getOrNull()?.delegation_responses } - val getUnboundingDelegations = async { stakeService.undelegations(address).getOrNull()?.unbonding_responses } - val getRewards = async { - stakeService.rewards(address).getOrNull()?.rewards - ?.associateBy { it.validator_address } - ?.mapValues { entry -> - entry.value.reward - .filter { it.denom == CosmosDenom.from(chain) } - .mapNotNull { - try { - BigInteger(it.amount.split(".")[0]) - } catch (_: Throwable) { - BigInteger.ZERO - } - } - .reduceOrNull { acc, value -> acc + value } - ?.toString() - } ?: emptyMap() - } - val delegations = getDelegations.await() - val undelegations = getUnboundingDelegations.await() - val rewards = getRewards.await() - - val baseDelegations = delegations?.map { - DelegationBase( - assetId = AssetId(chain), - state = DelegationState.Active, - balance = it.balance.amount, - completionDate = null, - delegationId = "", - validatorId = it.delegation.validator_address, - rewards = rewards[it.delegation.validator_address] ?: "0", - shares = "", - ) - } ?: emptyList() - - val baseUndelegations: List = undelegations?.map { undelegation -> - undelegation.entries.map { entry -> - DelegationBase( - assetId = AssetId(chain), - state = DelegationState.Pending, - balance = entry.balance, - completionDate = completionDateFormatter.parse(entry.completion_time)?.time, //2024-02-28T08:12:56.376120563Z - delegationId = entry.creation_height, - validatorId = undelegation.validator_address, - rewards = rewards[undelegation.validator_address] ?: "0", - shares = "", - ) - } - }?.flatten() ?: emptyList() - - (baseDelegations + baseUndelegations) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosTransactionStatusClient.kt deleted file mode 100644 index fdbdc35a3..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/CosmosTransactionStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosTransactionsService -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class CosmosTransactionStatusClient( - private val chain: Chain, - private val transactionsService: CosmosTransactionsService, -) : TransactionStatusClient { - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val tx = transactionsService.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - val state = when { - tx.tx_response == null || tx.tx_response.txhash.isEmpty() -> TransactionState.Pending - tx.tx_response.code == 0 -> TransactionState.Confirmed - else -> TransactionState.Reverted - } - return TransactionChanges(state) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosAccountsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosAccountsService.kt deleted file mode 100644 index 9ccbb2e0b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosAccountsService.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -import com.wallet.core.blockchain.cosmos.CosmosAccount -import com.wallet.core.blockchain.cosmos.CosmosAccountResponse -import com.wallet.core.blockchain.cosmos.CosmosBlockResponse -import com.wallet.core.blockchain.cosmos.CosmosInjectiveAccount -import retrofit2.http.GET -import retrofit2.http.Path - -interface CosmosAccountsService { - @GET("/cosmos/auth/v1beta1/accounts/{owner}") - suspend fun getAccountData(@Path("owner") owner: String): Result> - - @GET("/cosmos/auth/v1beta1/accounts/{owner}") - suspend fun getInjectiveAccountData(@Path("owner") owner: String): Result> - - @GET("/cosmos/base/tendermint/v1beta1/blocks/latest") - suspend fun getNodeInfo(): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosBalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosBalancesService.kt deleted file mode 100644 index 4e62720ee..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosBalancesService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -import com.wallet.core.blockchain.cosmos.CosmosBalances -import retrofit2.http.GET -import retrofit2.http.Path - -interface CosmosBalancesService { - @GET("/cosmos/bank/v1beta1/balances/{owner}") - suspend fun getBalance(@Path("owner") owner: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosBroadcastService.kt deleted file mode 100644 index b1f013e18..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosBroadcastService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -import com.wallet.core.blockchain.cosmos.CosmosBroadcastResponse -import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.POST - -interface CosmosBroadcastService { - @POST("/cosmos/tx/v1beta1/txs") - suspend fun broadcast(@Body body: RequestBody): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosNodeStatusService.kt deleted file mode 100644 index 2497c8c7a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosNodeStatusService.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -import com.wallet.core.blockchain.cosmos.CosmosBlockResponse -import com.wallet.core.blockchain.cosmos.CosmosSyncing -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Url - -interface CosmosNodeStatusService { - @GET//("/cosmos/base/tendermint/v1beta1/syncing") - suspend fun syncing(@Url url: String): Response - - @GET//("/cosmos/base/tendermint/v1beta1/blocks/latest") - suspend fun getNodeInfo(@Url url: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosRpcClient.kt deleted file mode 100644 index 81914b9d9..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosRpcClient.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -interface CosmosRpcClient : - CosmosBalancesService, - CosmosAccountsService, - CosmosStakeService, - CosmosTransactionsService, - CosmosBroadcastService, - CosmosNodeStatusService \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosStakeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosStakeService.kt deleted file mode 100644 index ba39a7326..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosStakeService.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -import com.wallet.core.blockchain.cosmos.CosmosDelegations -import com.wallet.core.blockchain.cosmos.CosmosRewards -import com.wallet.core.blockchain.cosmos.CosmosUnboundingDelegations -import com.wallet.core.blockchain.cosmos.CosmosValidators -import retrofit2.http.GET -import retrofit2.http.Path - -interface CosmosStakeService { - - @GET("/cosmos/staking/v1beta1/validators?pagination.limit=1000") - suspend fun validators(): Result - - @GET("/cosmos/staking/v1beta1/delegations/{address}") - suspend fun delegations(@Path("address") address: String): Result - - @GET("/cosmos/staking/v1beta1/delegators/{address}/unbonding_delegations") - suspend fun undelegations(@Path("address") address: String): Result - - @GET("/cosmos/distribution/v1beta1/delegators/{address}/rewards") - suspend fun rewards(@Path("address") address: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosTransactionsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosTransactionsService.kt deleted file mode 100644 index be1c4e5ba..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/cosmos/services/CosmosTransactionsService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos.services - -import com.wallet.core.blockchain.cosmos.CosmosTransactionResponse -import retrofit2.http.GET -import retrofit2.http.Path - -interface CosmosTransactionsService { - @GET("/cosmos/tx/v1beta1/txs/{txId}") - suspend fun transaction(@Path("txId") txId: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmBalanceClient.kt deleted file mode 100644 index b6409ec4d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmBalanceClient.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmBalancesService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.batch -import com.gemwallet.android.blockchain.clients.ethereum.services.createCallRequest -import com.gemwallet.android.blockchain.clients.ethereum.services.getBalance -import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.hexToBigInteger -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain - -class EvmBalanceClient( - private val chain: Chain, - private val callService: EvmCallService, - private val balancesService: EvmBalancesService, - private val smartChainStakeClient: SmartchainStakeClient, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - val availableValue = balancesService.getBalance(address) - .getOrNull()?.result?.value?.toString() - return AssetBalance.create(chain.asset(), available = availableValue ?: return null) - } - - override suspend fun getDelegationBalances(chain: Chain, address: String): AssetBalance? { - return when (chain) { - Chain.SmartChain -> smartChainStakeClient.getBalance(address) - else -> null - } - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - if (tokens.isEmpty()) { - return emptyList() - } - val result = mutableListOf() - val tokens = tokens.filter { it.id.tokenId != null } - val requests = tokens.map { token -> - callService.createCallRequest( - to = token.id.tokenId!!, - data = "0x70a08231000000000000000000000000${address.removePrefix("0x")}", - tag = "latest", - ) - } - val response = callService.batch(requests) - response.mapIndexedNotNull { index, data -> - val balance = data.hexToBigInteger() ?: return@mapIndexedNotNull null - val token = tokens[index] - result.add(AssetBalance.create(token, available = balance.toString())) - } - return result - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmBroadcastClient.kt deleted file mode 100644 index 2d3e0a184..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmBroadcastClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmBroadcastService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class EvmBroadcastClient( - private val chain: Chain, - private val broadcastService: EvmBroadcastService, -) : BroadcastClient { - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val request = JSONRpcRequest.create(EvmMethod.Broadcast, listOf(signedMessage.toHexString())) - val result = broadcastService.broadcast(request) - val data = result.getOrNull() ?: throw Exception(result.exceptionOrNull()?.message ?: "Network error") - if (data.error != null) { - throw Exception(data.error.message) - } - return data.result - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainData.kt new file mode 100644 index 000000000..b6ee803f7 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainData.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.blockchain.clients.ethereum + +import com.gemwallet.android.model.ChainSignData +import com.wallet.core.primitives.StakeData +import uniffi.gemstone.GemTransactionLoadMetadata +import java.math.BigInteger + +data class EvmChainData( + val chainId: Int, + val nonce: BigInteger, + val stakeData: StakeData?, +) : ChainSignData + + +fun GemTransactionLoadMetadata.Evm.toChainData(): EvmChainData { + return EvmChainData( + chainId = chainId.toInt(), + nonce = BigInteger.valueOf(nonce.toLong()), + stakeData = stakeData?.let { + StakeData( + data = it.data, + to = it.to + ) + } + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainExt.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainExt.kt index 93593ef92..1a46bf30f 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainExt.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmChainExt.kt @@ -3,13 +3,11 @@ package com.gemwallet.android.blockchain.clients.ethereum import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy import com.gemwallet.android.ext.type import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ConfirmParams import com.wallet.core.primitives.AssetId import com.wallet.core.primitives.AssetSubtype import com.wallet.core.primitives.EVMChain import com.wallet.core.primitives.NFTType -import uniffi.gemstone.Config import wallet.core.jni.AnyAddress import wallet.core.jni.EthereumAbi import wallet.core.jni.EthereumAbiFunction @@ -42,10 +40,6 @@ fun EVMChain.Companion.getDestinationAddress( } } -fun EVMChain.isOpStack(): Boolean { - return Config().getEvmChainConfig(string).isOpstack -} - fun EVMChain.Companion.encodeNFT(params: ConfirmParams.NftParams): String { return when (params.nftAsset.tokenType) { NFTType.ERC721 -> { diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmFeeCalculator.kt deleted file mode 100644 index aacd47360..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmFeeCalculator.kt +++ /dev/null @@ -1,160 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmFeeService -import com.gemwallet.android.blockchain.clients.ethereum.services.getFeeHistory -import com.gemwallet.android.blockchain.clients.ethereum.services.getGasLimit -import com.gemwallet.android.ext.toEVM -import com.gemwallet.android.ext.type -import com.gemwallet.android.math.hexToBigInteger -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.GasFee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetSubtype -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.EVMChain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import uniffi.gemstone.Config -import uniffi.gemstone.GemEthereumFeeHistory -import uniffi.gemstone.GemFeeCalculator -import uniffi.gemstone.GemPriorityFeeRecord -import wallet.core.jni.CoinType -import java.math.BigDecimal -import java.math.BigInteger -import java.util.Locale - -class EvmFeeCalculator( - private val feeService: EvmFeeService, - callService: EvmCallService, - coinType: CoinType -) { - - private val optimismGasOracle = OptimismGasOracle(callService, coinType) - - private val nativeGasLimit = BigInteger.valueOf(21_000L) - - suspend fun calculate( - params: ConfirmParams, // TODO: Outpack - assetId: AssetId, - recipient: String, - outputAmount: BigInteger, - payload: String?, - chainId: Int, - nonce: BigInteger, - ): List = withContext(Dispatchers.IO) { - val getGasLimit = async { getGasLimit(assetId, params.from.address, recipient, outputAmount, payload) } - val getBasePriorityFees = async { getBasePriorityFees(params) } - val gasLimit = getGasLimit.await() - val (baseFee, priorityFees) = getBasePriorityFees.await() - - if (params.assetId.chain.toEVM()?.isOpStack() == true) { - return@withContext priorityFees.mapIndexed { index, priorityFee -> - optimismGasOracle.estimate( - params = params, - chainId = chainId, - nonce = nonce, - gasLimit = gasLimit, - baseFee = baseFee, - priorityFee = priorityFee, - txSpeed = when (index) { - 0 -> FeePriority.Slow - 1 -> FeePriority.Normal - 2 -> FeePriority.Fast - else -> FeePriority.Normal - } - ) - } - } - - priorityFees.map { priorityFee -> - val value = priorityFee.value.toBigInteger() - val maxGasPrice: BigInteger = baseFee.plus(value) - val minerFee: BigInteger = when (params) { - is ConfirmParams.Stake, - is ConfirmParams.SwapParams, - is ConfirmParams.NftParams, - is ConfirmParams.TokenApprovalParams -> value - is ConfirmParams.TransferParams -> if (params.assetId.type() == AssetSubtype.NATIVE && params.isMax()) { - maxGasPrice - } else { - value - } - - is ConfirmParams.Activate -> throw IllegalArgumentException() - } - GasFee( - feeAssetId = AssetId(params.assetId.chain), - priority = FeePriority.entries.firstOrNull { it.string == priorityFee.priority.name.lowercase() } - ?: FeePriority.Normal, - limit = gasLimit, - maxGasPrice = maxGasPrice, - minerFee = minerFee, - ) - } - } - - private suspend fun getGasLimit( - assetId: AssetId, - from: String, - recipient: String, - outputAmount: BigInteger, - payload: String?, - ): BigInteger { - val (amount, to, data) = when (assetId.type()) { - AssetSubtype.NATIVE -> Triple(outputAmount, recipient, payload) - AssetSubtype.TOKEN -> Triple( - BigInteger.ZERO, // Amount - assetId.tokenId!!.lowercase(Locale.ROOT), // token - EVMChain.encodeTransactionData(assetId, payload, outputAmount, recipient).toHexString() - ) - } - - val gasLimit = try { - feeService.getGasLimit(from, to, amount, data) - } catch (err: Throwable) { - throw err - } - return if (gasLimit == nativeGasLimit) { - gasLimit - } else { - gasLimit.add(gasLimit.toBigDecimal().multiply(BigDecimal.valueOf(0.5)).toBigInteger()) - } - } - - internal suspend fun getHistory(chain: Chain, feeService: EvmFeeService): Pair { - val config = Config().getEvmChainConfig(chain.toEVM()?.string ?: throw IllegalArgumentException()) - val rewardsPercentiles = config.rewardsPercentiles - val feeHistory = feeService.getFeeHistory( - listOf(rewardsPercentiles.slow, rewardsPercentiles.normal, rewardsPercentiles.fast) - .map { it.toInt() } - ) ?: throw Exception("Unable to calculate base fee") - val baseFee = feeHistory.baseFeePerGas.mapNotNull { it.hexToBigInteger() }.maxOrNull() - ?: throw Exception("Unable to calculate base fee") - - return Pair( - baseFee, - GemEthereumFeeHistory( - reward = feeHistory.reward, - baseFeePerGas = feeHistory.baseFeePerGas, - gasUsedRatio = feeHistory.gasUsedRatio, - oldestBlock = feeHistory.oldestBlock, - ) - ) - } - - internal suspend fun getBasePriorityFees( - params: ConfirmParams, - ): Pair> { - val history = getHistory(params.asset.id.chain, feeService) - val calculator = GemFeeCalculator() - val priority = calculator.calculateBasePriorityFees( - chain = params.from.chain.string, - history = history.second - ) - return Pair(history.first, priority) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmGetTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmGetTokenClient.kt deleted file mode 100644 index 61a7223ae..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmGetTokenClient.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.GetTokenClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.batch -import com.gemwallet.android.blockchain.clients.ethereum.services.createCallRequest -import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.math.has0xPrefix -import com.gemwallet.android.math.hexToBigInteger -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import wallet.core.jni.EthereumAbi -import wallet.core.jni.EthereumAbiFunction -import wallet.core.jni.EthereumAbiValue - -class EvmGetTokenClient( - private val chain: Chain, - private val callService: EvmCallService, -) : GetTokenClient { - override suspend fun getTokenData(tokenId: String): Asset? = withContext(Dispatchers.IO) { - val params = listOf( - callService.createCallRequest(tokenId, EthereumAbi.encode(EthereumAbiFunction("name")).toHexString(), "latest"), - callService.createCallRequest(tokenId, EthereumAbi.encode(EthereumAbiFunction("symbol")).toHexString(), "latest"), - callService.createCallRequest(tokenId, EthereumAbi.encode(EthereumAbiFunction("decimals")).toHexString(), "latest"), - ) - val result = callService.batch(params) - val name = result.getOrNull(0)?.let { decodeAbi(it) } - val symbol = result.getOrNull(1)?.let { decodeAbi(it) } - val decimals = result.getOrNull(2)?.let { it.hexToBigInteger()?.toInt() } - - if (name.isNullOrEmpty() || symbol.isNullOrEmpty() || decimals == null) { - null - } else { - Asset( - id = AssetId(chain, tokenId), - name = name, - symbol = symbol, - decimals = decimals, - type = AssetType.ERC20, - ) - } - } - - override suspend fun isTokenQuery(query: String): Boolean = isTokenAddress(query) - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private fun decodeAbi(hexString: String): String? { - val data = hexString.decodeHex() - if (data.size < 32) { - return null - } - return EthereumAbiValue.decodeValue(data.drop(32).toByteArray(), "string") - } - - companion object { - fun isTokenAddress(tokenId: String): Boolean { - return tokenId.has0xPrefix() && tokenId.isNotEmpty() && tokenId.length == 42 - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmMethod.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmMethod.kt deleted file mode 100644 index 676b41804..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmMethod.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcMethod - -enum class EvmMethod(val value: String) : JSONRpcMethod { - GetBalance("eth_getBalance"), - GetGasLimit("eth_estimateGas"), - GetFeeHistory("eth_feeHistory"), - GetChainId("eth_chainId"), - GetNonce("eth_getTransactionCount"), - Broadcast("eth_sendRawTransaction"), - Call("eth_call"), - GetTransaction("eth_getTransactionReceipt"), - Sync("eth_syncing"), - GetBlockNumber("eth_blockNumber"), - ; - - override fun value(): String = value -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmNodeStatusClient.kt deleted file mode 100644 index c61a4d94a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmNodeStatusClient.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmNodeStatusService -import com.gemwallet.android.blockchain.clients.ethereum.services.getChainId -import com.gemwallet.android.blockchain.clients.ethereum.services.latestBlock -import com.gemwallet.android.blockchain.clients.ethereum.services.sync -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class EvmNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: EvmNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val getChainId = async { nodeStatusService.getChainId(url) } - val getLatestBlock = async { nodeStatusService.latestBlock(url).getOrNull()?.result?.value?.toString() } - val getSync = async { nodeStatusService.sync(url).getOrNull()?.result } - - val chainId = getChainId.await() - val blockNumber = getLatestBlock.await() ?: return@withContext null - val inSync = getSync.await() ?: return@withContext null - - NodeStatus( - url = url, - chainId = chainId.body()?.result?.value?.toString() ?: return@withContext null, - blockNumber = blockNumber, - inSync = !inSync, - latency = chainId.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignClient.kt index 20d6a86ca..25378779e 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignClient.kt @@ -6,12 +6,12 @@ import com.gemwallet.android.math.decodeHex import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.gemwallet.android.model.GasFee import com.google.protobuf.ByteString import com.wallet.core.primitives.AssetId import com.wallet.core.primitives.Chain import com.wallet.core.primitives.EVMChain -import com.wallet.core.primitives.FeePriority import com.wallet.core.primitives.NFTType import wallet.core.java.AnySigner import wallet.core.jni.AnyAddress @@ -46,14 +46,14 @@ class EvmSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val meta = chainData as EvmSignerPreloader.EvmChainData + val meta = chainData as EvmChainData val transfer = buildTransfer(finalAmount, finalAmount, params) val input = buildSignInput( assetId = params.assetId, - fee = meta.gasFee(feePriority), + fee = fee as GasFee, chainId = meta.chainId.toBigInteger(), nonce = meta.nonce, destinationAddress = params.destination().address, @@ -67,15 +67,15 @@ class EvmSignClient( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val meta = chainData as EvmSignerPreloader.EvmChainData + val meta = chainData as EvmChainData val amount = BigInteger.ZERO val transfer = buildTransfer(amount, finalAmount, params) val input = buildSignInput( assetId = params.assetId, - fee = meta.gasFee(feePriority), + fee = fee as GasFee, chainId = meta.chainId.toBigInteger(), nonce = meta.nonce, destinationAddress = params.destination().address, @@ -89,15 +89,15 @@ class EvmSignClient( params: ConfirmParams.TokenApprovalParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val meta = chainData as EvmSignerPreloader.EvmChainData + val meta = chainData as EvmChainData val amount = BigInteger.ZERO val transfer = buildTransfer(amount, finalAmount, params) val input = buildSignInput( assetId = params.assetId, - fee = meta.gasFee(feePriority), + fee = fee as GasFee, chainId = meta.chainId.toBigInteger(), nonce = meta.nonce, destinationAddress = params.destination()?.address ?: "", @@ -111,11 +111,12 @@ class EvmSignClient( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { + val fee = fee as GasFee val approvalData = params.approval - val chainData = chainData as EvmSignerPreloader.EvmChainData + val chainData = chainData as EvmChainData val amount = BigInteger(params.value) val approvalSign = if (approvalData != null) { @@ -128,12 +129,12 @@ class EvmSignClient( ), chainData = chainData, finalAmount = BigInteger.ZERO, - feePriority = feePriority, + fee = fee, privateKey = privateKey ) } else emptyList() - val fee = chainData.gasFee(feePriority).let { + val transferFee = fee.let { if (approvalData == null) { it } else { @@ -150,7 +151,7 @@ class EvmSignClient( val transfer = buildTransfer(amount, finalAmount, params) val swapInput = buildSignInput( assetId = AssetId(params.assetId.chain), - fee = fee, + fee = transferFee, chainId = chainData.chainId.toBigInteger(), nonce = chainData.nonce + if (approvalSign.isEmpty()) BigInteger.ZERO else BigInteger.ONE, destinationAddress = params.destination().address, @@ -166,60 +167,60 @@ class EvmSignClient( params: ConfirmParams.Stake.DelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return stakeSmartchain(params, chainData, finalAmount, feePriority, privateKey) + return stakeSmartchain(params, chainData, finalAmount, fee, privateKey) } override suspend fun signRedelegate( params: ConfirmParams.Stake.RedelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return stakeSmartchain(params, chainData, finalAmount, feePriority, privateKey) + return stakeSmartchain(params, chainData, finalAmount, fee, privateKey) } override suspend fun signRewards( params: ConfirmParams.Stake.RewardsParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return stakeSmartchain(params, chainData, finalAmount, feePriority, privateKey) + return stakeSmartchain(params, chainData, finalAmount, fee, privateKey) } override suspend fun signUndelegate( params: ConfirmParams.Stake.UndelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return stakeSmartchain(params, chainData, finalAmount, feePriority, privateKey) + return stakeSmartchain(params, chainData, finalAmount, fee, privateKey) } override suspend fun signWithdraw( params: ConfirmParams.Stake.WithdrawParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - return stakeSmartchain(params, chainData, finalAmount, feePriority, privateKey) + return stakeSmartchain(params, chainData, finalAmount, fee, privateKey) } override suspend fun signNft( params: ConfirmParams.NftParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val meta = chainData as EvmSignerPreloader.EvmChainData + val meta = chainData as EvmChainData val transfer = when (params.nftAsset.tokenType) { NFTType.ERC721 -> ERC721Transfer.newBuilder().apply { this.from = params.from.address @@ -237,7 +238,7 @@ class EvmSignClient( val input = buildSignInput( assetId = AssetId(chain, params.nftAsset.contractAddress), - fee = meta.gasFee(feePriority), + fee = fee as GasFee, chainId = meta.chainId.toBigInteger(), nonce = meta.nonce, destinationAddress = params.destination.address, @@ -251,19 +252,20 @@ class EvmSignClient( params: ConfirmParams.Stake, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { if (params.assetId.chain != Chain.SmartChain) { throw Exception("Doesn't support") } - val meta = chainData as EvmSignerPreloader.EvmChainData - val fee = meta.gasFee(feePriority) + val meta = chainData as EvmChainData + val toAddress = meta.stakeData?.to ?: throw java.lang.IllegalArgumentException("No stake data") + val stakeData = meta.stakeData.data?.decodeHex() ?: throw java.lang.IllegalArgumentException("No stake data") + val fee = fee as GasFee val valueData = when (params) { is ConfirmParams.Stake.DelegateParams -> finalAmount.toByteArray() else -> BigInteger.ZERO.toByteArray() } - val callData = StakeHub.encodeStake(params) val input = Ethereum.SigningInput.newBuilder().apply { this.txMode = Ethereum.TransactionMode.Enveloped this.maxFeePerGas = ByteString.copyFrom(fee.maxGasPrice.toByteArray()) @@ -271,12 +273,12 @@ class EvmSignClient( this.gasLimit = ByteString.copyFrom(fee.limit.toByteArray()) this.chainId = ByteString.copyFrom(meta.chainId.toBigInteger().toByteArray()) this.nonce = ByteString.copyFrom(meta.nonce.toByteArray()) - this.toAddress = StakeHub.address + this.toAddress = toAddress this.privateKey = ByteString.copyFrom(privateKey) this.transaction = Ethereum.Transaction.newBuilder().apply { contractGeneric = ContractGeneric.newBuilder().apply { amount = ByteString.copyFrom(valueData) - data = ByteString.copyFrom(callData.decodeHex()) + data = ByteString.copyFrom(stakeData) }.build() }.build() }.build() @@ -318,7 +320,7 @@ class EvmSignClient( val output = AnySigner.sign(input, coinType, Ethereum.SigningOutput.parser()) .encoded .toByteArray() - return listOf(output) + return listOf(output.toHexString("").toByteArray()) } override fun supported(chain: Chain): Boolean = this.chain == chain diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignerPreloader.kt deleted file mode 100644 index 12c598f04..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmSignerPreloader.kt +++ /dev/null @@ -1,153 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.ApprovalTransactionPreloader -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.NftTransactionPreloader -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmFeeService -import com.gemwallet.android.blockchain.clients.ethereum.services.getNonce -import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy -import com.gemwallet.android.ext.getNetworkId -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.GasFee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.EVMChain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import wallet.core.jni.AnyAddress -import wallet.core.jni.CoinType -import java.math.BigInteger - -class EvmSignerPreloader( - private val chain: Chain, - private val feeService: EvmFeeService, - callService: EvmCallService, -) : NativeTransferPreloader, - TokenTransferPreloader, - SwapTransactionPreloader, - StakeTransactionPreloader, - ApprovalTransactionPreloader, - NftTransactionPreloader { - - private val wcCoinType = WCChainTypeProxy().invoke(chain) - private val feeCalculator = EvmFeeCalculator(feeService, callService, wcCoinType) - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams = - preload(params.assetId, params.from, params.destination().address, params.amount, params.memo, params) - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams = - preload(params.assetId, params.from, params.destination().address, params.amount, params.memo, params) - - override suspend fun preloadNft(params: ConfirmParams.NftParams): SignerParams { - val memo = EVMChain.encodeNFT(params) - return preload(AssetId(params.assetId.chain, params.nftAsset.contractAddress), params.from, params.destination.address, params.amount, memo, params) - } - - override suspend fun preloadStake(params: ConfirmParams.Stake): SignerParams = - preload( - assetId = params.assetId, - from = params.from, - recipient = StakeHub.address, - outputAmount = when (params) { - is ConfirmParams.Stake.DelegateParams -> params.amount - else -> BigInteger.ZERO - }, - payload = when (params.assetId.chain) { - Chain.SmartChain -> StakeHub.encodeStake(params) - else -> throw IllegalArgumentException("Stake doesn't suppoted for chain ${params.assetId.chain} ") - }, - params = params, - ) - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - val approval = params.approval - val approvalData = if (approval != null) { - preloadApproval( - params = ConfirmParams.Builder(params.asset, params.from).approval( - approvalData = encodeApprove(AnyAddress(approval.spender, CoinType.ETHEREUM).data()).toHexString(), - provider = "", - contract = approval.token, - ), - ) - } else { - null - } - - val data = if (approvalData == null) { - preload( - assetId = AssetId(params.assetId.chain), - from = params.from, - recipient = params.to, - outputAmount = params.value.toBigInteger(), - payload = params.swapData, - params = params - ) - } else { - // Add approval fee - val chainData = (approvalData.chainData as EvmChainData) - val fees = chainData.fees.map { - GasFee( - feeAssetId = it.feeAssetId, - priority = it.priority, - limit = it.limit, - maxGasPrice = it.maxGasPrice, - minerFee = it.minerFee, - amount = it.limit.multiply(it.maxGasPrice).add(params.gasLimit!!.multiply(it.maxGasPrice)) - ) - } - SignerParams( - input = params, - chainData = chainData.copy(fees = fees), - ) - } - return data - } - - override suspend fun preloadApproval(params: ConfirmParams.TokenApprovalParams): SignerParams = - preload(params.assetId, params.from, params.contract, BigInteger.ZERO, params.data, params) - - private suspend fun preload( - assetId: AssetId, - from: Account, - recipient: String, - outputAmount: BigInteger, - payload: String?, - params: ConfirmParams, - ) = withContext(Dispatchers.IO) { - val nonce = feeService.getNonce(from.address) - val chainId = chain.getNetworkId().toIntOrNull() ?: throw Exception("Invalid chain") - val fees = feeCalculator.calculate( - params = params, - assetId = assetId, - recipient = recipient, - outputAmount = outputAmount, - payload = payload, - chainId = chainId, - nonce = nonce - ) - - SignerParams(params, EvmChainData(chainId, nonce, fees)) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class EvmChainData( - val chainId: Int, - val nonce: BigInteger, - val fees: List, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fees.firstOrNull { it.priority == speed } ?: fees.first() - - override fun allFee(): List = fees - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmTransactionStatusClient.kt deleted file mode 100644 index 6cdc7681f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/EvmTransactionStatusClient.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmTransactionsService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.math.hexToBigInteger -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import java.math.BigInteger - -class EvmTransactionStatusClient( - private val chain: Chain, - private val transactionsService: EvmTransactionsService, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - return getStatus(request.hash) - } - - private suspend fun getStatus(txId: String): TransactionChanges { - val request = JSONRpcRequest.create(EvmMethod.GetTransaction, listOf(txId)) - val resp = try { - transactionsService.transaction(request).result - } catch (_: Throwable) { - throw ServiceUnavailable - } - - if (resp.status != "0x0" && resp.status != "0x1") { - return TransactionChanges(TransactionState.Pending) - } - val state = when (resp.status) { - "0x0" -> TransactionState.Reverted - "0x1" -> TransactionState.Confirmed - else -> TransactionState.Confirmed - } - val gasUsed = resp.gasUsed.hexToBigInteger() ?: return TransactionChanges(TransactionState.Pending) - val effectiveGas = resp.effectiveGasPrice.hexToBigInteger() ?: return TransactionChanges(TransactionState.Pending) - val l1Fee = resp.l1Fee?.hexToBigInteger() ?: BigInteger.ZERO - val fee = gasUsed.multiply(effectiveGas) + l1Fee - - return TransactionChanges(state, fee) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/OptimismGasOracle.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/OptimismGasOracle.kt deleted file mode 100644 index a6e2b1834..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/OptimismGasOracle.kt +++ /dev/null @@ -1,144 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.ext.type -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.GasFee -import com.google.protobuf.ByteString -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetSubtype -import com.wallet.core.primitives.EVMChain -import com.wallet.core.primitives.FeePriority -import com.wallet.core.primitives.TransactionType -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import uniffi.gemstone.GemPriorityFeeRecord -import wallet.core.java.AnySigner -import wallet.core.jni.CoinType -import wallet.core.jni.EthereumAbi -import wallet.core.jni.EthereumAbiFunction -import wallet.core.jni.PrivateKey -import wallet.core.jni.proto.Ethereum -import wallet.core.jni.proto.Ethereum.Transaction.Transfer -import java.math.BigInteger - -class OptimismGasOracle( - private val callService: EvmCallService, - private val coinType: CoinType, -) { - - suspend fun estimate( - params: ConfirmParams, - chainId: Int, - nonce: BigInteger, - baseFee: BigInteger, - priorityFee: GemPriorityFeeRecord, - gasLimit: BigInteger, - txSpeed: FeePriority, - ): GasFee = withContext(Dispatchers.IO) { - val priorityFeeValue = priorityFee.value.toBigInteger() - val assetId = params.assetId - val feeAssetId = AssetId(assetId.chain) - val gasPrice = baseFee + priorityFeeValue - val minerFee = when (params.getTxType()) { - TransactionType.Transfer -> if (assetId.type() == AssetSubtype.NATIVE && params.isMax()) gasPrice else priorityFeeValue - TransactionType.Swap, TransactionType.TokenApproval -> priorityFeeValue - else -> throw IllegalAccessException("Operation doesn't available") - } - val amount = when (params.getTxType()) { - TransactionType.Transfer -> if (params.isMax()) params.amount - gasLimit * gasPrice else params.amount - TransactionType.TokenApproval, TransactionType.Swap -> params.amount - else -> throw IllegalAccessException("Operation doesn't available") - } - val encoded = encode( - assetId = assetId, - coin = coinType, - amount = amount, - destinationAddress = when (params) { - is ConfirmParams.SwapParams -> params.to - is ConfirmParams.TokenApprovalParams -> params.contract - is ConfirmParams.TransferParams -> params.destination.address - else -> throw IllegalArgumentException() - }, - meta = when (params) { - is ConfirmParams.SwapParams -> params.swapData - is ConfirmParams.TokenApprovalParams -> params.data - else -> params.memo() - }, - chainId = chainId, - nonce = nonce, - gasFee = GasFee( - feeAssetId = feeAssetId, - priority = FeePriority.Normal, - limit = gasLimit, - maxGasPrice = gasPrice, - minerFee = minerFee, - ), - ) - val l2Fee = gasPrice * gasLimit - val l1Fee = getL1Fee(encoded) ?: throw IllegalStateException("Can't get L1 Fee") - GasFee( - feeAssetId = feeAssetId, - priority = txSpeed, - maxGasPrice = gasPrice, - minerFee = minerFee, - limit = gasLimit, - amount = l1Fee + l2Fee, - ) - } - - private suspend fun getL1Fee(data: ByteArray): BigInteger? { - val abiFn = EthereumAbiFunction("getL1Fee").apply { - this.addParamBytes(data, false) - } - val encodedFn = EthereumAbi.encode(abiFn) - val request = JSONRpcRequest.create( - EvmMethod.Call, - listOf( - mapOf( - "to" to "0x420000000000000000000000000000000000000F", - "data" to encodedFn.toHexString(), - ), - "latest", - ) - ) - return callService.callNumber(request).getOrNull()?.result?.value - } - - private fun encode( - assetId: AssetId, - coin: CoinType, - destinationAddress: String, - amount: BigInteger, - meta: String?, - chainId: Int, - nonce: BigInteger, - gasFee: GasFee, - ): ByteArray { - val transfer = Transfer.newBuilder().apply { - this.amount = ByteString.copyFrom(amount.toByteArray()) - this.data = ByteString.copyFrom( - EVMChain.encodeTransactionData(assetId, meta, amount, destinationAddress) - ) - }.build() - val signInput = EvmSignClient(assetId.chain).buildSignInput( - assetId = assetId, - fee = gasFee, - chainId = chainId.toBigInteger(), - nonce = nonce, - destinationAddress = destinationAddress, - transfer = transfer, - privateKey = PrivateKey().data(), - ) - val signer = AnySigner.sign(signInput, coin, Ethereum.SigningOutput.parser()) - val signatureLenInRlp = 67 // 1 + 32 + 1 + 32 + 1 - val encoded = signer.encoded.toList().dropLast(signatureLenInRlp).toMutableList() - when (assetId.type()) { - AssetSubtype.NATIVE -> encoded.removeAt(2) - else -> {} - } - return encoded.toByteArray() - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/SmartchainStakeClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/SmartchainStakeClient.kt deleted file mode 100644 index ef290d015..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/SmartchainStakeClient.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.blockchain.clients.StakeClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmCallService -import com.gemwallet.android.blockchain.clients.ethereum.services.batch -import com.gemwallet.android.blockchain.clients.ethereum.services.callString -import com.gemwallet.android.blockchain.clients.ethereum.services.createCallRequest -import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationState -import com.wallet.core.primitives.DelegationValidator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import wallet.core.jni.EthereumAbiValue -import java.math.BigInteger - -class SmartchainStakeClient( - private val chain: Chain, - private val callService: EvmCallService, -) : StakeClient { - - override suspend fun getValidators(chain: Chain, apr: Double): List { - val limit = getMaxElectedValidators() - val data = StakeHub.encodeValidatorsCall(0, limit) - val result = callService.callString(StakeHub.reader, data) ?: return emptyList() - val validators = StakeHub.decodeValidatorsReturn(result) - return validators - } - - override suspend fun getStakeDelegations(chain: Chain, address: String, apr: Double): List = withContext(Dispatchers.IO) { - val limit = 128 - val delegationDataRequest = StakeHub.encodeDelegationsCall(address, limit) - val undelegationDataRequest = StakeHub.encodeUndelegationsCall(address, limit) - val requests = listOf( - callService.createCallRequest(StakeHub.reader, delegationDataRequest, "latest"), - callService.createCallRequest(StakeHub.reader, undelegationDataRequest, "latest"), - ) - val result = callService.batch(requests) - val delegations = StakeHub.decodeDelegationsResult(result[0]) - val undelegations = StakeHub.decodeUnelegationsResult(result[1]) - - delegations + undelegations - } - - suspend fun getBalance(address: String): AssetBalance? = withContext(Dispatchers.IO) { - val delegations = getStakeDelegations(chain, address, 0.0) - - val staked = delegations.filter { it.state == DelegationState.Active }.sumBalances() - - val pending = delegations.filter { - it.state == DelegationState.Undelegating || it.state == DelegationState.AwaitingWithdrawal - }.sumBalances() - - AssetBalance.create( - asset = Chain.SmartChain.asset(), - staked = staked.toString(), - pending = pending.toString() - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private suspend fun getMaxElectedValidators(): Int { - val result = callService.callString(StakeHub.address, StakeHub.encodeMaxElectedValidators()) - ?: throw IllegalStateException("Unable to get validators") - return EthereumAbiValue.decodeUInt256(result.decodeHex()).toUShort().toInt() - } - - private fun List.sumBalances(): BigInteger = - map { it.balance.toBigIntegerOrNull() ?: BigInteger.ZERO } - .fold(BigInteger.ZERO) {acc, value -> acc + value } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/StakeHub.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/StakeHub.kt deleted file mode 100644 index 3479269d8..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/StakeHub.kt +++ /dev/null @@ -1,140 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum - -import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.ConfirmParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationState -import com.wallet.core.primitives.DelegationValidator -import uniffi.gemstone.BscDelegation -import uniffi.gemstone.BscDelegationStatus - -object StakeHub { - val offset: UShort = (0).toUShort() - const val address = "0x0000000000000000000000000000000000002002" - const val reader = "0x830295c0abe7358f7e24bc38408095621474280b" - - fun encodeMaxElectedValidators(): String { - // cast calldata "maxElectedValidators()" - return "0xc473318f" - } - - fun encodeStake(params: ConfirmParams): String { - return when (params) { - is ConfirmParams.Stake.DelegateParams -> encodeDelegateCall(params.validatorId, false) - - is ConfirmParams.Stake.RedelegateParams -> encodeRedelegateCall(params, false) - is ConfirmParams.Stake.UndelegateParams -> encodeUndelegateCall(params) - is ConfirmParams.Stake.WithdrawParams -> encodeClaim(params, (0).toULong()) - else -> throw IllegalArgumentException() - }.toHexString() - } - - fun encodeDelegateCall(validator: String, delegateVote: Boolean): ByteArray { - return uniffi.gemstone.bscEncodeDelegateCall(validator, delegateVote) - } - - fun encodeValidatorsCall(offset: Int, limit: Int): String { - return uniffi.gemstone.bscEncodeValidatorsCall(offset.toUShort(), limit.toUShort()) - .toHexString() - } - - fun decodeValidatorsReturn(hexData: String): List { - return uniffi.gemstone.bscDecodeValidatorsReturn(hexData.decodeHex()).map { - DelegationValidator( - chain = Chain.SmartChain, - id = it.operatorAddress, - name = it.moniker, - isActive = !it.jailed, - commision = it.commission.toDouble() / 100, - apr = it.apy.toDouble() / 100, - ) - } - } - - fun encodeDelegationsCall(address: String, limit: Int): String { - return uniffi.gemstone.bscEncodeDelegationsCall(address, offset, limit.toUShort()) - .toHexString() - } - - fun decodeDelegationsResult(data: String): List { - return uniffi.gemstone.bscDecodeDelegationsReturn(data.decodeHex()).map { it.into() } - } - - fun encodeUndelegationsCall(address: String, limit: Int): String { - return uniffi.gemstone.bscEncodeUndelegationsCall(address, offset, limit.toUShort()) - .toHexString() - } - - fun decodeUnelegationsResult(data: String): List { - return uniffi.gemstone.bscDecodeUndelegationsReturn(data.decodeHex()).map { it.into() } - } - - fun encodeUndelegateCall(params: ConfirmParams.Stake.UndelegateParams): ByteArray { - val amountShare = - params.amount * params.share!!.toBigInteger() / params.balance!!.toBigInteger() - return uniffi.gemstone.bscEncodeUndelegateCall( - operatorAddress = params.validatorId, - shares = amountShare.toString() - ) - } - - fun encodeRedelegateCall( - params: ConfirmParams.Stake.RedelegateParams, - votePower: Boolean - ): ByteArray { - val amountShare = - params.amount * params.share!!.toBigInteger() / params.balance!!.toBigInteger() - return uniffi.gemstone.bscEncodeRedelegateCall( - srcValidator = params.srcValidatorId, - dstValidator = params.dstValidatorId, - shares = amountShare.toString(), - delegateVotePower = votePower, - ) - } - - fun encodeClaim( - params: ConfirmParams.Stake.WithdrawParams, - requestNumber: ULong - ): ByteArray { - return uniffi.gemstone.bscEncodeClaimCall( - operatorAddress = params.validatorId, - requestNumber = requestNumber - ) - } -} - -fun BscDelegation.into(): DelegationBase { - val completion = when (status) { - BscDelegationStatus.ACTIVE -> null - BscDelegationStatus.UNDELEGATING -> unlockTime?.toLong() - }?.toLong() - val state = when (status) { - BscDelegationStatus.ACTIVE -> DelegationState.Active - BscDelegationStatus.UNDELEGATING -> { - if (completion == null) { - DelegationState.Undelegating - } else if (System.currentTimeMillis() <= completion * 1000) { - DelegationState.Undelegating - } else { - DelegationState.AwaitingWithdrawal - } - } - } - val delegationId = when (status) { - BscDelegationStatus.ACTIVE -> "" - BscDelegationStatus.UNDELEGATING -> "$validatorAddress--${unlockTime ?: 0}" - } - return DelegationBase( - assetId = Chain.SmartChain.asset().id, - state = state, - balance = amount, - shares = shares, - rewards = "0", - completionDate = completion, - delegationId = delegationId, - validatorId = validatorAddress, - ) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmBalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmBalancesService.kt deleted file mode 100644 index 856a7c419..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmBalancesService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.blockchain.clients.ethereum.EvmMethod -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient.EvmNumber -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import retrofit2.http.Body -import retrofit2.http.POST - -interface EvmBalancesService { - @POST("/") - suspend fun getBalance(@Body request: JSONRpcRequest>): Result> -} - -suspend fun EvmBalancesService.getBalance(address: String): Result> { - return getBalance( - JSONRpcRequest.create( - method = EvmMethod.GetBalance, - params = listOf(address, "latest") - ) - ) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmBroadcastService.kt deleted file mode 100644 index 62d14fb71..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmBroadcastService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import retrofit2.http.Body -import retrofit2.http.POST - -interface EvmBroadcastService { - @POST("/") - suspend fun broadcast(@Body request: JSONRpcRequest>): Result> -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmCallService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmCallService.kt deleted file mode 100644 index aa5ffe11a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmCallService.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.blockchain.clients.ethereum.EvmMethod -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient.EvmNumber -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import retrofit2.http.Body -import retrofit2.http.POST - -interface EvmCallService { - @POST("/") - suspend fun callString(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun callNumber(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun callBatch(@Body request: List>>): Result>> -} - -suspend fun EvmCallService.callString(contract: String, hexData: String): String? { - val params = mapOf( - "to" to contract, - "data" to hexData - ) - val request = JSONRpcRequest.create( - EvmMethod.Call, - listOf( - params, - "latest" - ) - ) - return callString(request).getOrNull()?.result -} - -suspend fun EvmCallService.batch(requests: List>>): List { - val result = callBatch(requests) - return result.getOrNull()?.map { it.result } ?: emptyList() -} - -fun EvmCallService.createCallRequest(to: String, data: String, tag: String? = null): JSONRpcRequest> { - val params = mapOf( - "to" to to, - "data" to data - ) - return JSONRpcRequest.create( - EvmMethod.Call, - listOf( - params, - tag - ).filterNotNull() - ) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmFeeService.kt deleted file mode 100644 index 34f53ed53..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmFeeService.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.blockchain.clients.ethereum.EvmMethod -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient.EvmNumber -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.gemwallet.android.math.append0x -import com.wallet.core.blockchain.ethereum.EthereumFeeHistory -import retrofit2.http.Body -import retrofit2.http.POST -import java.math.BigInteger - -interface EvmFeeService { - @POST("/") - suspend fun getFeeHistory(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun getGasLimit(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun getNonce(@Body request: JSONRpcRequest>): Result> -} - -internal suspend fun EvmFeeService.getFeeHistory(rewardPercentiles: List): EthereumFeeHistory? { - return getFeeHistory(JSONRpcRequest.create(EvmMethod.GetFeeHistory, listOf("10", "latest", rewardPercentiles))) - .getOrNull()?.result -} - -internal suspend fun EvmFeeService.getGasLimit(from: String, to: String, amount: BigInteger, data: String?): BigInteger { - val transaction = mapOf( - "from" to from, - "to" to to, - "value" to "0x${amount.toString(16)}", - "data" to if (data.isNullOrEmpty()) "0x" else data.append0x(), - ) - val request = JSONRpcRequest.create(EvmMethod.GetGasLimit, listOf(transaction)) - val result = getGasLimit(request) - return result.getOrNull()?.result?.value - ?: throw Exception("Fail calculate gas limit") -} - -internal suspend fun EvmFeeService.getNonce(fromAddress: String): BigInteger { - val nonceParams = listOf(fromAddress, "latest") - return getNonce(JSONRpcRequest.create(EvmMethod.GetNonce, nonceParams)) - .getOrNull()?.result?.value ?: throw Exception("Fail get current nonce") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmNodeStatusService.kt deleted file mode 100644 index c76b5a395..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmNodeStatusService.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.blockchain.clients.ethereum.EvmMethod -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient.EvmNumber -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST -import retrofit2.http.Url - -interface EvmNodeStatusService { - @POST - suspend fun chainId(@Url url: String, @Body request: JSONRpcRequest>): Response> - - @POST - suspend fun sync(@Url url: String, @Body request: JSONRpcRequest>): Result> - - @POST - suspend fun latestBlock(@Url url: String, @Body request: JSONRpcRequest>): Result> -} - -internal suspend fun EvmNodeStatusService.getChainId(url: String): Response> { - return chainId(url, JSONRpcRequest.create(EvmMethod.GetChainId, emptyList())) -} - -internal suspend fun EvmNodeStatusService.latestBlock(url: String): Result> { - return latestBlock(url, JSONRpcRequest.create(EvmMethod.GetBlockNumber, emptyList())) -} - -internal suspend fun EvmNodeStatusService.sync(url: String): Result> { - return sync(url, JSONRpcRequest.create(EvmMethod.Sync, emptyList())) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmRpcClient.kt deleted file mode 100644 index e2ae06d1f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmRpcClient.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.math.hexToBigInteger -import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonDeserializer -import com.google.gson.JsonElement -import wallet.core.jni.EthereumAbiValue -import java.lang.reflect.Type -import java.math.BigInteger - -interface EvmRpcClient : - EvmCallService, - EvmBalancesService, - EvmFeeService, - EvmNodeStatusService, - EvmBroadcastService, - EvmTransactionsService -{ - class EvmNumber( - val value: BigInteger?, - ) - - class TokenBalance( - val value: BigInteger?, - ) - - class BalanceDeserializer : JsonDeserializer { - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext? - ): EvmNumber { - return EvmNumber( - try { - json?.asString?.hexToBigInteger() - } catch (_: Throwable) { - null - } - ) - } - } - - class TokenBalanceDeserializer : JsonDeserializer { - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext? - ): TokenBalance { - return TokenBalance( - try { - EthereumAbiValue.decodeUInt256(json?.asString?.decodeHex()).toBigIntegerOrNull() - } catch (_: Throwable) { - null - } - ) - } - - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmTransactionsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmTransactionsService.kt deleted file mode 100644 index 1d9850956..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ethereum/services/EvmTransactionsService.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ethereum.services - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.ethereum.EthereumTransactionReciept -import retrofit2.http.Body -import retrofit2.http.POST - -interface EvmTransactionsService { - @POST("/") - suspend fun transaction(@Body request: JSONRpcRequest>): JSONRpcResponse -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/hyper/HyperCoreSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/hyper/HyperCoreSignClient.kt new file mode 100644 index 000000000..611d174e0 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/hyper/HyperCoreSignClient.kt @@ -0,0 +1,10 @@ +package com.gemwallet.android.blockchain.clients.hyper + +import com.gemwallet.android.blockchain.clients.SignClient +import com.wallet.core.primitives.Chain + +class HyperCoreSignClient( + val chain: Chain, +) : SignClient { + override fun supported(chain: Chain): Boolean = this.chain == chain +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearBalanceClient.kt deleted file mode 100644 index b23ecb7e6..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearBalanceClient.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Chain - -class NearBalanceClient( - private val chain: Chain, - private val rpcClient: NearRpcClient, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - return rpcClient.account( - JSONRpcRequest( - method = NearMethod.Query.value, - params = mapOf( - "request_type" to "view_account", - "finality" to "final", - "account_id" to address, - ) - ) - ).fold( - { - if (it.error == null) { - AssetBalance.create(chain.asset(), it.result.amount) - } else { - null - } - } - ) { - null - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearBroadcastClient.kt deleted file mode 100644 index 000bc5b18..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearBroadcastClient.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class NearBroadcastClient( - private val chain: Chain, - private val rpcClient: NearRpcClient, -) : BroadcastClient { - override suspend fun send( - account: Account, - signedMessage: ByteArray, - type: TransactionType - ): String { - return rpcClient.broadcast( - JSONRpcRequest( - NearMethod.Broadcast.value, - params = mapOf( - "signed_tx_base64" to String(signedMessage) - ) - ) - ).getOrThrow().result.transaction.hash - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearChainData.kt new file mode 100644 index 000000000..c9420ce58 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearChainData.kt @@ -0,0 +1,16 @@ +package com.gemwallet.android.blockchain.clients.near + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class NearChainData( + val block: String, + val sequence: ULong, +) : ChainSignData + +fun GemTransactionLoadMetadata.Near.toChainData(): NearChainData { + return NearChainData( + block = blockHash, + sequence = sequence + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearMethod.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearMethod.kt deleted file mode 100644 index ef0e1f9cf..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearMethod.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -enum class NearMethod(val value: String) { - GasPrice("gas_price"), - Query("query"), - LatestBlock("block"), - Transaction("tx"), - Broadcast("send_tx"), -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearNodeStatusClient.kt deleted file mode 100644 index 630fb9b4a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearNodeStatusClient.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class NearNodeStatusClient( - private val chain: Chain, - private val rpcClient: NearRpcClient, -) : NodeStatusClient { - - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val getBlock = async { - rpcClient.latestBlock( - url, - JSONRpcRequest( - NearMethod.LatestBlock.value, - mapOf("finality" to "final") - ) - ) - } - val block = getBlock.await() - NodeStatus( - url = url, - blockNumber = block.body()?.result?.header?.height?.toString() ?: return@withContext null, - chainId = "", - inSync = true, - latency = block.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearRpcClient.kt deleted file mode 100644 index 477b12c69..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearRpcClient.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.gemwallet.android.math.decodeHex -import com.wallet.core.blockchain.near.NearAccount -import com.wallet.core.blockchain.near.NearAccountAccessKey -import com.wallet.core.blockchain.near.NearBlock -import com.wallet.core.blockchain.near.NearBroadcastResult -import com.wallet.core.blockchain.near.NearGasPrice -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST -import retrofit2.http.Url -import wallet.core.jni.Base58 - -interface NearRpcClient { - @POST("/") - suspend fun getGasPrice(@Body params: JSONRpcRequest>): Result> - - @POST("/") - suspend fun account(@Body params: JSONRpcRequest): Result> - - @POST("/") - suspend fun accountAccessKey(@Body params: JSONRpcRequest): Result> - - @POST("/") - suspend fun latestBlock(@Body params: JSONRpcRequest): Result> - - @POST("/") - suspend fun transaction(@Body params: JSONRpcRequest): Result> - - @POST("/") - suspend fun broadcast(@Body params: JSONRpcRequest): Result> - - @POST - suspend fun latestBlock(@Url url: String, @Body params: JSONRpcRequest): Response> -} - -suspend fun NearRpcClient.accountAccessKey(from: String, ): NearAccountAccessKey { - val publicKey = "ed25519:" + Base58.encodeNoCheck(from.decodeHex()) - return accountAccessKey( - JSONRpcRequest( - method = NearMethod.Query.value, - params = mapOf( - "request_type" to "view_access_key", - "finality" to "final", - "account_id" to from, - "public_key" to publicKey, - ) - ) - ).getOrNull()?.result ?: throw IllegalStateException("Can't get account") -} - -suspend fun NearRpcClient.latestBlock(): NearBlock { - return latestBlock( - JSONRpcRequest( - method = NearMethod.LatestBlock.value, - params = mapOf( - "finality" to "final", - ) - ) - ).getOrNull()?.result ?: throw IllegalStateException("Can't get block") -} - -suspend fun NearRpcClient.getGasPrice(): NearGasPrice { - return getGasPrice( - JSONRpcRequest( - method = NearMethod.GasPrice.value, - params = listOf(null), - ) - ).getOrNull()?.result ?: throw IllegalStateException("Can't get gas price") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignClient.kt index 120b21394..a487a962f 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignClient.kt @@ -4,9 +4,9 @@ import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.java.AnySigner import wallet.core.jni.Base58 import wallet.core.jni.Base64 @@ -21,14 +21,14 @@ class NearSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val metadata = chainData as NearSignerPreloader.NearChainData + val metadata = chainData as NearChainData val input = NEAR.SigningInput.newBuilder().apply { this.signerId = params.from.address - this.nonce = metadata.sequence + this.nonce = metadata.sequence.toLong() this.receiverId = params.destination().address this.addAllActions( listOf( diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignerPreloader.kt deleted file mode 100644 index 6aed5bfc6..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearSignerPreloader.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class NearSignerPreloader( - private val chain: Chain, - private val rpcClient: NearRpcClient, -) : NativeTransferPreloader { - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams = withContext(Dispatchers.IO) { - val getAccountJob = async { rpcClient.accountAccessKey(params.from.address) } - val blockJob = async { rpcClient.latestBlock() } - - val account = getAccountJob.await() - val block = blockJob.await() - - val fee = BigInteger("900000000000000000000") - - SignerParams( - input = params, - chainData = NearChainData( - sequence = account.nonce + 1L, - block = block.header.hash, - fee = Fee( - feeAssetId = AssetId(chain), - priority = FeePriority.Normal, - amount = fee, - ) - ) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class NearChainData( - val block: String, - val sequence: Long, - val fee: Fee, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearTransactionStatusClient.kt deleted file mode 100644 index d504f7d29..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/near/NearTransactionStatusClient.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.gemwallet.android.blockchain.clients.near - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionError -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class NearTransactionStatusClient( - private val chain: Chain, - private val rpcClient: NearRpcClient, -) : TransactionStatusClient { - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val resp = rpcClient.transaction( - JSONRpcRequest( - method = NearMethod.Transaction.value, - params = mapOf( - "tx_hash" to request.hash, - "sender_account_id" to request.sender, - "wait_until" to "EXECUTED", - ), - ) - ).getOrNull() ?: throw ServiceUnavailable - if (resp.error != null) { - throw TransactionError(resp.error.message) - } - return when (resp.result.final_execution_status) { - "FINAL" -> TransactionChanges(state = TransactionState.Confirmed) - else -> TransactionChanges(state = TransactionState.Pending) - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotBalancesClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotBalancesClient.kt deleted file mode 100644 index 43599591d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotBalancesClient.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotBalancesService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Chain -import java.math.BigInteger - -class PolkadotBalancesClient( - private val chain: Chain, - private val balancesService: PolkadotBalancesService -) : BalanceClient { - - override suspend fun getNativeBalance( - chain: Chain, - address: String - ): AssetBalance? { - try { - val resp = balancesService.balance(address).getOrNull() ?: return null - val free = resp.free.toBigInteger() - val reserved = resp.reserved.toBigInteger() - val available = (free - reserved).max(BigInteger.ZERO) - return AssetBalance.create( - chain.asset(), - available = available.toString(), - reserved = reserved.toString(), - ) - } catch (_: Throwable) { - return null - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotBroadcastClient.kt deleted file mode 100644 index 27dd8c411..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotBroadcastClient.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotBroadcastService -import com.gemwallet.android.math.toHexString -import com.wallet.core.blockchain.polkadot.PolkadotTransactionPayload -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class PolkadotBroadcastClient( - private val chain: Chain, - private val broadcastService: PolkadotBroadcastService, -) : BroadcastClient { - override suspend fun send( - account: Account, - signedMessage: ByteArray, - type: TransactionType - ): String { - val resp = broadcastService.broadcast(PolkadotTransactionPayload(signedMessage.toHexString())).getOrNull() - ?: throw Exception("Polkadot service unavailable") - return if (resp.hash.isNullOrEmpty()) { - throw Exception(resp.cause ?: resp.error ?: "Broadcast error") - } else { - resp.hash - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotChainData.kt new file mode 100644 index 000000000..bc4112f4e --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotChainData.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.blockchain.clients.polkadot + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class PolkadotChainData( + val sequence: ULong, + val genesisHash: String, + val blockHash: String, + val blockNumber: ULong, + val specVersion: ULong, + val transactionVersion: ULong, + val period: Long, +) : ChainSignData + +fun GemTransactionLoadMetadata.Polkadot.toChainData(): PolkadotChainData { + return PolkadotChainData( + sequence = sequence, + genesisHash = genesisHash, + blockHash = blockHash, + blockNumber = blockNumber, + specVersion = specVersion, + transactionVersion = transactionVersion, + period = period.toLong(), + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotFeeCalculator.kt deleted file mode 100644 index 94055e461..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotFeeCalculator.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot - -import com.gemwallet.android.model.Fee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import java.math.BigInteger - -class PolkadotFeeCalculator { - fun calculate(): Fee = Fee(priority = FeePriority.Normal, feeAssetId = AssetId(Chain.Polkadot), amount = BigInteger.ONE) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotGatewayEstimateFee.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotGatewayEstimateFee.kt new file mode 100644 index 000000000..762823397 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotGatewayEstimateFee.kt @@ -0,0 +1,63 @@ +package com.gemwallet.android.blockchain.clients.polkadot + +import com.gemwallet.android.math.append0x +import com.gemwallet.android.math.toHexString +import com.google.protobuf.ByteString +import uniffi.gemstone.Chain +import uniffi.gemstone.GemGatewayEstimateFee +import uniffi.gemstone.GemTransactionLoadFee +import uniffi.gemstone.GemTransactionLoadInput +import uniffi.gemstone.GemTransactionLoadMetadata +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Polkadot +import java.math.BigInteger + +class PolkadotGatewayEstimateFee : GemGatewayEstimateFee { + override suspend fun getFee( + chain: Chain, + input: GemTransactionLoadInput + ): GemTransactionLoadFee? = null + + override suspend fun getFeeData( + chain: Chain, + input: GemTransactionLoadInput + ): String? { + val metadata = (input.metadata as? GemTransactionLoadMetadata.Polkadot) + ?.toChainData() + ?: throw IllegalArgumentException("Incorrect metadata: wait polkadot") + + val transactionData = transactionPayload( + toAdresss = input.destinationAddress, + value = input.value.toBigInteger(), + data = metadata, + ) + return transactionData + } + + fun transactionPayload(toAdresss: String, value: BigInteger, data: PolkadotChainData): String { + val input = Polkadot.SigningInput.newBuilder().apply { + this.genesisHash = ByteString.copyFrom(data.genesisHash.toByteArray()) + this.blockHash = ByteString.copyFrom(data.blockHash.toByteArray()) + this.nonce = data.sequence.toLong() + this.specVersion = data.specVersion.toInt() + this.network = CoinType.POLKADOT.ss58Prefix() + this.transactionVersion = data.transactionVersion.toInt() + this.privateKey = ByteString.copyFrom(PrivateKey().data()) + this.era = Polkadot.Era.newBuilder().apply { + this.blockNumber = data.blockNumber.toLong() + this.period = data.period + }.build() + this.balanceCall = Polkadot.Balance.newBuilder().apply { + transfer = Polkadot.Balance.Transfer.newBuilder().apply { + this.toAddress = toAdresss + this.value = ByteString.copyFrom(value.toByteArray()) + }.build() + }.build() + }.build() + + val output = AnySigner.sign(input, CoinType.POLKADOT, Polkadot.SigningOutput.parser()) + return output.encoded.toByteArray().toHexString().append0x() + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotNodeStatusClient.kt deleted file mode 100644 index 5cf623209..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotNodeStatusClient.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotNodeStatusService -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class PolkadotNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: PolkadotNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus( - chain: Chain, - url: String - ): NodeStatus? = withContext(Dispatchers.IO) { - val getBlock = async { nodeStatusService.blockHead("$url/blocks/head") } - val getVersion = async { nodeStatusService.nodeVersion("$url/node/version") } - - val version = getVersion.await() - val block = getBlock.await() - - NodeStatus( - url = url, - chainId = version.body()?.chain ?: return@withContext null, - blockNumber = block.body()?.number ?: return@withContext null, - inSync = true, - latency = version.getLatency() - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignClient.kt index a34f99d8c..df902c3df 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignClient.kt @@ -1,18 +1,15 @@ package com.gemwallet.android.blockchain.clients.polkadot import com.gemwallet.android.blockchain.clients.SignClient -import com.gemwallet.android.blockchain.clients.polkadot.models.PolkadotSigningData -import com.gemwallet.android.math.append0x import com.gemwallet.android.math.decodeHex import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.java.AnySigner import wallet.core.jni.CoinType -import wallet.core.jni.PrivateKey import wallet.core.jni.proto.Polkadot import java.math.BigInteger @@ -24,22 +21,21 @@ class PolkadotSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = (chainData as? PolkadotSignerPreloaderClient.PolkadotChainData) ?: throw Exception("incomplete data") - val data = chainData.data + val chainData = (chainData as? PolkadotChainData) ?: throw Exception("incomplete data") val input = Polkadot.SigningInput.newBuilder().apply { - this.genesisHash = ByteString.copyFrom(data.genesisHash.decodeHex()) - this.blockHash = ByteString.copyFrom(data.blockHash.decodeHex()) + this.genesisHash = ByteString.copyFrom(chainData.genesisHash.decodeHex()) + this.blockHash = ByteString.copyFrom(chainData.blockHash.decodeHex()) this.nonce = chainData.sequence.toLong() - this.specVersion = data.specVersion.toInt() + this.specVersion = chainData.specVersion.toInt() this.network = CoinType.POLKADOT.ss58Prefix() - this.transactionVersion = data.transactionVersion.toInt() + this.transactionVersion = chainData.transactionVersion.toInt() this.privateKey = ByteString.copyFrom(privateKey) this.era = Polkadot.Era.newBuilder().apply { - this.blockNumber = data.blockNumber.toLong() - this.period = data.period + this.blockNumber = chainData.blockNumber.toLong() + this.period = chainData.period }.build() this.balanceCall = Polkadot.Balance.newBuilder().apply { transfer = Polkadot.Balance.Transfer.newBuilder().apply { @@ -49,36 +45,8 @@ class PolkadotSignClient( }.build() }.build() val output = AnySigner.sign(input, CoinType.POLKADOT, Polkadot.SigningOutput.parser()) - return listOf(output.encoded.toByteArray()) + return listOf(output.encoded.toByteArray().toHexString().toByteArray()) } override fun supported(chain: Chain): Boolean = this.chain == chain - - companion object { - fun transactionPayload(toAdresss: String, value: BigInteger, nonce: Long, data: PolkadotSigningData): String { - val input = Polkadot.SigningInput.newBuilder().apply { - this.genesisHash = ByteString.copyFrom(data.genesisHash.toByteArray()) - this.blockHash = ByteString.copyFrom(data.blockHash.toByteArray()) - this.nonce = nonce - this.specVersion = data.specVersion.toInt() - this.network = CoinType.POLKADOT.ss58Prefix() - this.transactionVersion = data.transactionVersion.toInt() - this.privateKey = ByteString.copyFrom(PrivateKey().data()) - this.era = Polkadot.Era.newBuilder().apply { - this.blockNumber = data.blockNumber.toLong() - this.period = data.period - }.build() - this.balanceCall = Polkadot.Balance.newBuilder().apply { - transfer = Polkadot.Balance.Transfer.newBuilder().apply { - this.toAddress = toAdresss - this.value = ByteString.copyFrom(value.toByteArray()) - }.build() - }.build() - }.build() - - val output = AnySigner.sign(input, CoinType.POLKADOT, Polkadot.SigningOutput.parser()) - return output.encoded.toByteArray().toHexString().append0x() - } - - } } \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignerPreloaderClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignerPreloaderClient.kt deleted file mode 100644 index 0bc191960..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotSignerPreloaderClient.kt +++ /dev/null @@ -1,90 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.polkadot.models.PolkadotSigningData -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotBalancesService -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotFeeService -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotTransactionService -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.blockchain.polkadot.PolkadotTransactionPayload -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class PolkadotSignerPreloaderClient( - private val chain: Chain, - private val transactionService: PolkadotTransactionService, - private val feeService: PolkadotFeeService, - private val balancesService: PolkadotBalancesService, -) : NativeTransferPreloader { - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams = withContext(Dispatchers.IO) { - val getTransactionMaterial = async { transactionService.transactionMaterial().getOrNull() } - val getBalance = async { balancesService.balance(params.destination.address).getOrNull() } - val getNonce = async { balancesService.balance(params.from.address).getOrNull()?.nonce?.toLong() } - - val transactionMaterial = getTransactionMaterial.await() ?: throw Exception("Can't load chain data") - val balance = getBalance.await() ?: throw Exception("Can't load chain data") - val nonce = getNonce.await() ?: throw Exception("Can't load nonce") - -// TODO: Check reserved 1DOT -// if (Crypto(balance.reserved).value(chain.asset().decimals) < BigDecimal.ONE) { -// throw IllegalStateException("Doesn't active recipient") -// } - - val signData = PolkadotSigningData( - genesisHash = transactionMaterial.genesisHash, - blockHash = transactionMaterial.at.hash, - blockNumber = transactionMaterial.at.height.toBigInteger(), - specVersion = transactionMaterial.specVersion.toBigInteger(), - transactionVersion = transactionMaterial.txVersion.toBigInteger(), - period = periodLength - ) - - val transactionData = PolkadotSignClient.transactionPayload( - params.destination.address, - params.amount, - nonce = nonce, - data = signData, - ) - val feeAmount = feeService.fee(PolkadotTransactionPayload(transactionData)).getOrNull()?.partialFee?.toBigInteger() - ?: throw java.lang.Exception("Can't estimate fee") - val fee = Fee( - priority = FeePriority.Normal, - feeAssetId = AssetId(chain), - amount = feeAmount - ) - SignerParams( - input = params, - chainData = PolkadotChainData( - sequence = nonce.toInt(), - data = signData, - blockNumber = signData.blockNumber.toInt(), - fee = fee - ) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class PolkadotChainData( - val sequence: Int, - val data: PolkadotSigningData, - val blockNumber: Int, - val fee: Fee - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - - override fun blockNumber(): String = blockNumber.toString() - } - - companion object { - const val periodLength: Long = 64 - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotTransactionStatusClient.kt deleted file mode 100644 index d1870c149..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/PolkadotTransactionStatusClient.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotTransactionService -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import java.math.BigInteger - -class PolkadotTransactionStatusClient( - private val chain: Chain, - private val transactionService: PolkadotTransactionService, -) : TransactionStatusClient { - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val blockNumber = try { - request.block.toBigInteger() - } catch (_: Throwable) { - BigInteger.ZERO - } - if (blockNumber < BigInteger.ZERO) { - throw Exception("Invalid block number") - } - val blockHead = transactionService.blockHead().getOrNull()?.number?.toBigInteger() ?: throw ServiceUnavailable - val fromBlock = request.block - val toBlock = blockHead.min(blockNumber + BigInteger.valueOf(PolkadotSignerPreloaderClient.periodLength)) - val blocks = transactionService.blocks("$fromBlock-$toBlock").getOrNull() ?: emptyList() - for (block in blocks) { - for (extr in block.extrinsics) { - if (extr.hash == request.hash) { - val state = if (extr.success) TransactionState.Confirmed else TransactionState.Failed - return TransactionChanges(state) - } - } - } - return TransactionChanges(TransactionState.Pending) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/models/PolkadotSigningData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/models/PolkadotSigningData.kt deleted file mode 100644 index da417bbe9..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/models/PolkadotSigningData.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.models - -import com.gemwallet.android.serializer.BigIntegerSerializer -import kotlinx.serialization.Serializable -import java.math.BigInteger - -@Serializable -data class PolkadotSigningData( - val genesisHash: String, - val blockHash: String, - @Serializable(BigIntegerSerializer::class) val blockNumber: BigInteger, - @Serializable(BigIntegerSerializer::class) val specVersion: BigInteger, - @Serializable(BigIntegerSerializer::class) val transactionVersion: BigInteger, - val period: Long, -) diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/models/PolkadotTransactionBroadcast.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/models/PolkadotTransactionBroadcast.kt deleted file mode 100644 index 40928a698..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/models/PolkadotTransactionBroadcast.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.models - -import kotlinx.serialization.Serializable - -@Serializable -data class PolkadotTransactionBroadcast( - val hash: String?, - val error: String?, - val cause: String?, -) diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotBalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotBalancesService.kt deleted file mode 100644 index 1675e586b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotBalancesService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.services - -import com.wallet.core.blockchain.polkadot.PolkadotAccountBalance -import retrofit2.http.GET -import retrofit2.http.Path - -interface PolkadotBalancesService { - @GET("/accounts/{address}/balance-info") - suspend fun balance(@Path("address") address: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotBroadcastService.kt deleted file mode 100644 index 17053d2f8..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotBroadcastService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.services - -import com.gemwallet.android.blockchain.clients.polkadot.models.PolkadotTransactionBroadcast -import com.wallet.core.blockchain.polkadot.PolkadotTransactionPayload -import retrofit2.http.Body -import retrofit2.http.POST - -interface PolkadotBroadcastService { - @POST("/transaction") - suspend fun broadcast(@Body data: PolkadotTransactionPayload): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotFeeService.kt deleted file mode 100644 index 9e918f33a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotFeeService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.services - -import com.wallet.core.blockchain.polkadot.PolkadotEstimateFee -import com.wallet.core.blockchain.polkadot.PolkadotTransactionPayload -import retrofit2.http.Body -import retrofit2.http.POST - -interface PolkadotFeeService { - @POST("/transaction/fee-estimate") - suspend fun fee(@Body data: PolkadotTransactionPayload): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotNodeStatusService.kt deleted file mode 100644 index df5bc9bde..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotNodeStatusService.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.services - -import com.wallet.core.blockchain.polkadot.PolkadotBlock -import com.wallet.core.blockchain.polkadot.PolkadotNodeVersion -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Url - -interface PolkadotNodeStatusService { - @GET//(/node/version) - suspend fun nodeVersion(@Url url: String): Response - - @GET//("/blocks/head") - suspend fun blockHead(@Url url: String): Response -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotServices.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotServices.kt deleted file mode 100644 index c1dfdb69d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotServices.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.services - -interface PolkadotServices : PolkadotBalancesService, - PolkadotBroadcastService, - PolkadotFeeService, - PolkadotNodeStatusService, - PolkadotTransactionService \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotTransactionService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotTransactionService.kt deleted file mode 100644 index 843ab7dc1..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/polkadot/services/PolkadotTransactionService.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.gemwallet.android.blockchain.clients.polkadot.services - -import com.wallet.core.blockchain.polkadot.PolkadotBlock -import com.wallet.core.blockchain.polkadot.PolkadotTransactionMaterial -import retrofit2.http.GET -import retrofit2.http.Query - -interface PolkadotTransactionService { - @GET("/transaction/material?noMeta=true") - suspend fun transactionMaterial(): Result - - @GET("/blocks/head") - suspend fun blockHead(): Result - - @GET("/blocks?noFees=true") - suspend fun blocks(@Query("range") range: String): Result> -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaBalanceClient.kt deleted file mode 100644 index ae1f82ff6..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaBalanceClient.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.solana.services.SolanaAccountsService -import com.gemwallet.android.blockchain.clients.solana.services.SolanaBalancesService -import com.gemwallet.android.blockchain.clients.solana.services.SolanaStakeService -import com.gemwallet.android.blockchain.clients.solana.services.getBalance -import com.gemwallet.android.blockchain.clients.solana.services.getDelegationsBalance -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class SolanaBalanceClient( - val chain: Chain, - val accountsService: SolanaAccountsService, - val balancesService: SolanaBalancesService, - val stakeService: SolanaStakeService, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? = withContext(Dispatchers.IO) { - val available = balancesService.getBalance(address) ?: return@withContext null - AssetBalance.create(chain.asset(), available.toString()) - } - - override suspend fun getDelegationBalances(chain: Chain, address: String): AssetBalance? { - val staked = stakeService.getDelegationsBalance(address) - return AssetBalance.create(chain.asset(), staked = staked.toString()) - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - val accountsRequests = tokens.map { - JSONRpcRequest.create( - method = SolanaMethod.GetTokenAccountByOwner, - params = listOf( - address, - mapOf("mint" to it.id.tokenId!!), - mapOf("encoding" to "jsonParsed"), - ) - ) - } - - val responseAccountOwner = try { - accountsService.batchAccount(accountsRequests) - } catch (err: Throwable) { - throw err - } - val balances = responseAccountOwner.mapIndexed { index, value -> - val balance = value.result.value.firstOrNull()?.let { account -> - account.account.data.parsed.info.tokenAmount.amount.toBigIntegerOrNull() - } ?: BigInteger.ZERO - AssetBalance.create(tokens[index], available = balance.toString()) - } - return balances - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaBroadcastClient.kt deleted file mode 100644 index abe5ebf8f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaBroadcastClient.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.solana.services.SolanaBroadcastService -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import java.nio.charset.StandardCharsets - -class SolanaBroadcastClient( - private val chain: Chain, - private val rpcClient: SolanaBroadcastService, -) : BroadcastClient { - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val encodedMessage = signedMessage.toString(StandardCharsets.UTF_8) - val params = if (type == TransactionType.Swap) { - listOf( - encodedMessage, - mapOf( - "encoding" to "base64", - "skipPreflight" to true, - ), - ) - } else { - listOf( - encodedMessage, - mapOf("encoding" to "base64"), - ) - } - val request = JSONRpcRequest.create(SolanaMethod.SendTransaction, params) - val response = rpcClient.broadcast(request).getOrNull() ?: throw ServiceError.NetworkError - return if (response.error == null) { - response.result - } else { - throw Exception(response.error.message) - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaChainData.kt new file mode 100644 index 000000000..862eb00df --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaChainData.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.blockchain.clients.solana + +import com.gemwallet.android.model.ChainSignData +import com.wallet.core.primitives.SolanaTokenProgramId +import uniffi.gemstone.GemSolanaTokenProgramId +import uniffi.gemstone.GemTransactionLoadMetadata + +data class SolanaChainData( + val blockhash: String, + val senderTokenAddress: String?, + val recipientTokenAddress: String?, + val tokenProgram: SolanaTokenProgramId?, +) : ChainSignData + +fun GemTransactionLoadMetadata.Solana.toChainData(): SolanaChainData { + return SolanaChainData( + blockhash = blockHash, + senderTokenAddress = senderTokenAddress, + recipientTokenAddress = recipientTokenAddress, + tokenProgram = when (tokenProgram) { + GemSolanaTokenProgramId.TOKEN -> SolanaTokenProgramId.Token + GemSolanaTokenProgramId.TOKEN2022 -> SolanaTokenProgramId.Token2022 + null -> null + }, + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaFeeCalculator.kt deleted file mode 100644 index 8552ddf66..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaFeeCalculator.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.solana.services.SolanaFeeService -import com.gemwallet.android.blockchain.clients.solana.services.getPriorityFees -import com.gemwallet.android.ext.type -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.GasFee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetSubtype -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import uniffi.gemstone.Config -import java.math.BigInteger -import kotlin.math.max -import kotlin.math.min - -class SolanaFeeCalculator( - private val feeService: SolanaFeeService -) { - - private val staticBaseFee = 5_000L - private val tokenAccountSize = 165 - - suspend fun calculate(params: ConfirmParams): List = when (params) { - is ConfirmParams.Stake -> calculate(params) - is ConfirmParams.SwapParams -> calculate(params) - is ConfirmParams.TokenApprovalParams -> throw IllegalArgumentException("Token approval doesn't support") - is ConfirmParams.TransferParams.Generic -> calculate(params) - is ConfirmParams.TransferParams -> calculate(params) - is ConfirmParams.NftParams, - is ConfirmParams.Activate -> throw IllegalArgumentException() - } - - suspend fun calculate(params: ConfirmParams.Stake): List { - return calculate( - gasLimit = 100_000L, - multipleOf = 50_000, - ) - } - - suspend fun calculate(params: ConfirmParams.TransferParams.Generic): List { - return calculate( - gasLimit = 420_000L, - multipleOf = 250_000, - ) - } - - suspend fun calculate(params: ConfirmParams.TransferParams): List { - return calculate( - gasLimit = 100_000L, - multipleOf = if (params.assetId.type() == AssetSubtype.NATIVE) 50_000 else 100_000, - ) - } - - suspend fun calculate(params: ConfirmParams.SwapParams): List { - return calculate( - gasLimit = 420_000L, - multipleOf = 250_000, - ) - } - - private suspend fun calculate(gasLimit: Long, multipleOf: Long): List { - val priorityFees = feeService.getPriorityFees() - - return FeePriority.entries.map { speed -> - val speedCoefficient = when (speed) { - FeePriority.Slow -> 0.5f - FeePriority.Normal -> 1f - FeePriority.Fast -> 3f - } - val minerFee = if (priorityFees.isEmpty()) { - multipleOf - } else { - val averagePriorityFee = priorityFees.map { it.prioritizationFee }.sortedDescending() - .subList(0, min(5, priorityFees.size - 1)) - .fold(0L) { acc, i -> acc + i } / priorityFees.size - max(((averagePriorityFee + multipleOf - 1) / multipleOf) * multipleOf, multipleOf) - } * speedCoefficient - val tokenAccountCreation = Config().getChainConfig(Chain.Solana.string).tokenActivationFee?.toBigInteger() ?: BigInteger.ZERO - val totalFee = staticBaseFee + (minerFee * gasLimit / 1_000_000) - - GasFee( - feeAssetId = AssetId(Chain.Solana), - priority = speed, - minerFee = minerFee.toLong().toBigInteger(), - maxGasPrice = staticBaseFee.toBigInteger(), - limit = gasLimit.toBigInteger(), - amount = totalFee.toLong().toBigInteger(), - options = mapOf("tokenAccountCreation" to tokenAccountCreation) - ) - } - } - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaMethod.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaMethod.kt deleted file mode 100644 index 5b2d947d7..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaMethod.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcMethod - -enum class SolanaMethod(val value: String) : JSONRpcMethod { - GetBalance("getBalance"), - GetTokenBalance("getTokenAccountBalance"), - GetTokenAccountByOwner("getTokenAccountsByOwner"), - RentExemption("getMinimumBalanceForRentExemption"), - GetLatestBlockhash("getLatestBlockhash"), - GetPriorityFee("getRecentPrioritizationFees"), - SendTransaction("sendTransaction"), - GetTransaction("getTransaction"), - GetValidators("getVoteAccounts"), - GetDelegations("getProgramAccounts"), - GetEpoch("getEpochInfo"), - GetAccountInfo("getAccountInfo"), - GetHealth("getHealth"), - GetSlot("getSlot"), - GetGenesisHash("getGenesisHash") - ; - - override fun value(): String = value -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaNodeStatusClient.kt deleted file mode 100644 index 099fdd61c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaNodeStatusClient.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.solana.services.SolanaNodeStatusService -import com.gemwallet.android.blockchain.clients.solana.services.genesisHash -import com.gemwallet.android.blockchain.clients.solana.services.health -import com.gemwallet.android.blockchain.clients.solana.services.slot -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class SolanaNodeStatusClient( - private val chain: Chain, - private val rpcClient: SolanaNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val inSyncJob = async { rpcClient.health(url) } - val slotJob = async { rpcClient.slot(url).getOrNull()?.result } - val chainIdJob = async { rpcClient.genesisHash(url).getOrNull()?.result } - - val inSync = inSyncJob.await() - - NodeStatus( - url = url, - inSync = inSync.body()?.result == "ok", - blockNumber = slotJob.await().toString(), - chainId = chainIdJob.await() ?: return@withContext null, - latency = inSync.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaRawTxDecoder.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaRawTxDecoder.kt index 9b33c0994..a1aab962c 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaRawTxDecoder.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaRawTxDecoder.kt @@ -13,23 +13,4 @@ class SolanaRawTxDecoder( fun signatureCount(): Byte { return decodeShortVecLength(offset = 0) } - - fun signatures(): ByteArray { - var offset = 0 - val count = decodeShortVecLength(offset = offset) - - var result: ByteArray = byteArrayOf() - for (i in 0 ..< count) { - val sig = rawData.sliceArray(offset ..< (offset + 64)) - result += sig - offset += 64 - } - return result - } - - fun messageData(): List { - val sigCount = decodeShortVecLength(offset = 0).toInt() - val offset = 1 + sigCount * 64 - return rawData.slice(offset ..< rawData.size) - } } \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignClient.kt index 3c542c7c0..211f3fde0 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignClient.kt @@ -4,13 +4,13 @@ import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.blockchain.operators.GetAsset import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.gemwallet.android.model.GasFee import com.gemwallet.android.serializer.jsonEncoder import com.google.protobuf.ByteString import com.wallet.core.blockchain.solana.SolanaAccountMeta import com.wallet.core.blockchain.solana.SolanaInstruction import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import com.wallet.core.primitives.SolanaTokenProgramId import wallet.core.java.AnySigner import wallet.core.jni.Base58 @@ -46,7 +46,7 @@ class SolanaSignClient( params: ConfirmParams.TransferParams.Generic, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val input = params.memo ?: throw java.lang.IllegalArgumentException("No data") @@ -77,10 +77,10 @@ class SolanaSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val blockhash = (chainData as SolanaSignerPreloader.SolanaChainData).blockhash + val blockhash = (chainData as SolanaChainData).blockhash val input = Solana.SigningInput.newBuilder().apply { this.transferTransaction = Solana.Transfer.newBuilder().apply { this.recipient = params.destination().address @@ -92,24 +92,25 @@ class SolanaSignClient( this.recentBlockhash = blockhash this.privateKey = ByteString.copyFrom(privateKey) } - return sign(input = input, fee = chainData.gasFee()) + return sign(input = input, fee = fee as GasFee) } override suspend fun signTokenTransfer( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val decimals = getAsset.getAsset(params.assetId)?.decimals ?: throw IllegalArgumentException("Asset not found") val tokenId = params.assetId.tokenId val amount = finalAmount.toLong() val recipient = params.destination().address - val metadata = chainData as SolanaSignerPreloader.SolanaChainData + val metadata = chainData as SolanaChainData val tokenProgramId = when (metadata.tokenProgram) { SolanaTokenProgramId.Token -> Solana.TokenProgramId.TokenProgram SolanaTokenProgramId.Token2022 -> Solana.TokenProgramId.Token2022Program + null -> throw IllegalArgumentException("Not token program id") } val input = Solana.SigningInput.newBuilder().apply { this.recentBlockhash = metadata.blockhash @@ -145,17 +146,17 @@ class SolanaSignClient( }.build() } } - return sign(input, chainData.gasFee()) + return sign(input, fee as GasFee) } override suspend fun signSwap( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val fee = chainData.gasFee(feePriority) + val fee = fee as GasFee val feePrice = fee.minerFee val feeLimit = fee.limit val encodedTx = params.swapData @@ -182,7 +183,7 @@ class SolanaSignClient( params: ConfirmParams.Stake.DelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val instruction = SolanaInstruction( @@ -194,16 +195,16 @@ class SolanaSignClient( ) val data = jsonEncoder.encodeToString(instruction) - val recentBlockhash = (chainData as SolanaSignerPreloader.SolanaChainData).blockhash + val recentBlockhash = (chainData as SolanaChainData).blockhash val signInput = Solana.SigningInput.newBuilder().apply { this.recentBlockhash = recentBlockhash this.delegateStakeTransaction = Solana.DelegateStake.newBuilder().apply { - this.validatorPubkey = params.validatorId + this.validatorPubkey = params.validator.id this.value = finalAmount.toLong() }.build() this.privateKey = ByteString.copyFrom(privateKey) } - val encoded = sign(input = signInput, fee = chainData.gasFee()) + val encoded = sign(input = signInput, fee = fee as GasFee) val transaction = SolanaTransaction.insertInstruction(String(encoded.firstOrNull() ?: throw Exception()), -1, data) return signRawTransaction(transaction, privateKey) } @@ -212,37 +213,37 @@ class SolanaSignClient( params: ConfirmParams.Stake.UndelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val recentBlockhash = (chainData as SolanaSignerPreloader.SolanaChainData).blockhash + val recentBlockhash = (chainData as SolanaChainData).blockhash val signInput = Solana.SigningInput.newBuilder().apply { this.recentBlockhash = recentBlockhash this.deactivateStakeTransaction = Solana.DeactivateStake.newBuilder().apply { - this.stakeAccount = params.delegationId + this.stakeAccount = params.delegation.base.delegationId }.build() this.privateKey = ByteString.copyFrom(privateKey) } - return sign(input = signInput, fee = chainData.gasFee()) + return sign(input = signInput, fee = fee as GasFee) } override suspend fun signWithdraw( params: ConfirmParams.Stake.WithdrawParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val recentBlockhash = (chainData as SolanaSignerPreloader.SolanaChainData).blockhash + val recentBlockhash = (chainData as SolanaChainData).blockhash val signInput = Solana.SigningInput.newBuilder().apply { this.recentBlockhash = recentBlockhash this.withdrawTransaction = Solana.WithdrawStake.newBuilder().apply { - stakeAccount = params.delegationId + stakeAccount = params.delegation.base.delegationId value = finalAmount.toLong() }.build() this.privateKey = ByteString.copyFrom(privateKey) } - return sign(input = signInput, fee = chainData.gasFee()) + return sign(input = signInput, fee = fee as GasFee) } private fun sign(input: Solana.SigningInput.Builder, fee: GasFee): List { @@ -284,6 +285,7 @@ class SolanaSignClient( override fun supported(chain: Chain): Boolean = this.chain == chain } + //public struct SolanaRawTxDecoder { // let rawData: Data // diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignerPreloader.kt deleted file mode 100644 index 1e1b0459c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaSignerPreloader.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.GenericTransferPreloader -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.solana.services.SolanaAccountsService -import com.gemwallet.android.blockchain.clients.solana.services.SolanaFeeService -import com.gemwallet.android.blockchain.clients.solana.services.SolanaNetworkInfoService -import com.gemwallet.android.blockchain.clients.solana.services.createAccountByOwnerRequest -import com.gemwallet.android.blockchain.clients.solana.services.getBlockhash -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.GasFee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import com.wallet.core.primitives.SolanaTokenProgramId -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import uniffi.gemstone.Config - -class SolanaSignerPreloader( - private val chain: Chain, - feeService: SolanaFeeService, - private val networkInfoService: SolanaNetworkInfoService, - private val accountsService: SolanaAccountsService, -) : GenericTransferPreloader, NativeTransferPreloader, TokenTransferPreloader, SwapTransactionPreloader, StakeTransactionPreloader { - - private val feeCalculator = SolanaFeeCalculator(feeService) - - override suspend fun preloadGeneric(params: ConfirmParams.TransferParams.Generic): SignerParams { - return preload(params) - } - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - return preload(params, "", null, SolanaTokenProgramId.Token) - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams = withContext(Dispatchers.IO) { - val tokenId = params.assetId.tokenId!! - val owner = params.from.address - - val requests = listOf( - accountsService.createAccountByOwnerRequest(owner, tokenId), - accountsService.createAccountByOwnerRequest(params.destination.address, tokenId), - ) - val accounts = try { - accountsService.batchAccount(requests) - } catch (_: Throwable) { - throw Exception("Can't load account info") - } - val senderToken = accounts.getOrNull(0)?.result?.value?.firstOrNull() ?: throw Exception("Sender token address is empty") - val recipientTokenAccounts = accounts.getOrNull(1)?.result?.value?.firstOrNull()?.pubkey - val senderTokenAddress = senderToken.pubkey - val tokenProgram = Config().getSolanaTokenProgramId(senderToken.account.owner)?.let { - when (it) { - SolanaTokenProgramId.Token.string -> SolanaTokenProgramId.Token - SolanaTokenProgramId.Token2022.string -> SolanaTokenProgramId.Token2022 - else -> null - } - } ?: throw Exception("Unknow token program id") - preload(params, senderTokenAddress, recipientTokenAccounts, tokenProgram) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - return preload(params, "", null, SolanaTokenProgramId.Token) - } - - override suspend fun preloadStake(params: ConfirmParams.Stake): SignerParams { - return preload(params, "", null, SolanaTokenProgramId.Token) - } - - private suspend fun preload( - params: ConfirmParams, - senderTokenAddress: String = "", - recipientTokenAddress: String? = null, - tokenProgram: SolanaTokenProgramId = SolanaTokenProgramId.Token - ): SignerParams = withContext(Dispatchers.IO) { - val blockHashJob = async { networkInfoService.getBlockhash() } - val feeJob = async { feeCalculator.calculate(params) } - - val (fee, blockHash) = Pair(feeJob.await(), blockHashJob.await()) - - val chainData = SolanaChainData(blockHash, senderTokenAddress, recipientTokenAddress, tokenProgram, fee) - SignerParams(params, chainData) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class SolanaChainData( - val blockhash: String, - val senderTokenAddress: String, - val recipientTokenAddress: String?, - val tokenProgram: SolanaTokenProgramId, - val fees: List, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fees.firstOrNull { it.priority == speed } ?: fees.first() - - override fun allFee(): List = fees - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaStakeClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaStakeClient.kt deleted file mode 100644 index 8e81ada32..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaStakeClient.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.StakeClient -import com.gemwallet.android.blockchain.clients.solana.services.SolanaStakeService -import com.gemwallet.android.blockchain.clients.solana.services.delegations -import com.gemwallet.android.blockchain.clients.solana.services.epoch -import com.gemwallet.android.blockchain.clients.solana.services.validators -import com.gemwallet.android.ext.asset -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationState -import com.wallet.core.primitives.DelegationValidator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class SolanaStakeClient( - private val chain: Chain, - private val stakeService: SolanaStakeService, -): StakeClient { - override suspend fun getValidators(chain: Chain, apr: Double): List { - return stakeService.validators()?.map { - val isActive = it.epochVoteAccount - DelegationValidator( - chain = chain, - id = it.votePubkey, - name = "", - isActive = isActive, - commision = it.commission.toDouble(), - apr = if (isActive) apr - apr * (it.commission.toDouble() / 100) else 0.0, - ) - } ?: emptyList() - } - - override suspend fun getStakeDelegations(chain: Chain, address: String, apr: Double): List = withContext(Dispatchers.IO) { - val getEpoch = async { stakeService.epoch() } - val getDelegations = async { stakeService.delegations(address) } - val epoch = getEpoch.await() ?: return@withContext emptyList() - val delegations = getDelegations.await() ?: return@withContext emptyList() - val nextEpoch = System.currentTimeMillis() + ((epoch.slotsInEpoch - epoch.slotIndex) * 420) - - delegations.map { delegation -> - val info = delegation.account.data.parsed.info - val deactivateEpoch = try { - info.stake.delegation.deactivationEpoch.toLong() - } catch (_: Throwable) { - null - } - val activationEpoch = try { - info.stake.delegation.activationEpoch.toLong() - } catch (_: Throwable) { - null - } - val state = fun(): DelegationState { - if (deactivateEpoch != null) { - if (deactivateEpoch == epoch.epoch) { - return DelegationState.Deactivating - } else if (deactivateEpoch < epoch.epoch) { - return DelegationState.AwaitingWithdrawal - } - } else if (activationEpoch != null) { - if (activationEpoch == epoch.epoch) { - return DelegationState.Activating - } else if (activationEpoch <= epoch.epoch) { - return DelegationState.Active - } - } - return DelegationState.Pending - }() - val balance = delegation.account.lamports.toString() - DelegationBase( - assetId = chain.asset().id, - state = state, - balance = balance, - rewards = (BigInteger(balance) - BigInteger(info.stake.delegation.stake)).toString(), - delegationId = delegation.pubkey, - completionDate = nextEpoch, - validatorId = info.stake.delegation.voter, - shares = "", - ) - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaTokenClient.kt deleted file mode 100644 index 2e311ab44..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaTokenClient.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.GetTokenClient -import com.gemwallet.android.blockchain.clients.solana.services.SolanaAccountsService -import com.gemwallet.android.blockchain.clients.solana.services.createAccountInfoRequest -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import wallet.core.jni.Base58 - -class SolanaTokenClient( - private val chain: Chain, - private val accountsService: SolanaAccountsService, -) : GetTokenClient { - - override suspend fun getTokenData(tokenId: String): Asset? = withContext(Dispatchers.IO) { - val tokenInfo = try { - accountsService.getAccountInfoSpl(accountsService.createAccountInfoRequest(tokenId)) - .result.value.data.parsed.info - } catch (_: Throwable) { - return@withContext null - } - // spl 2022 - if (tokenInfo.extensions != null) { - val extension = tokenInfo.extensions.firstOrNull { it.extension == "tokenMetadata" } - ?: throw Exception("no tokenMetadata") - Asset( - id = AssetId(chain = chain, tokenId = tokenId), - name = extension.state.name ?: return@withContext null, - symbol = extension.state.symbol ?: return@withContext null, - decimals = tokenInfo.decimals, - type = AssetType.SPL, - ) - } - - val metadataKey = try { - uniffi.gemstone.solanaDeriveMetadataPda(tokenId) - } catch (_: Throwable) { - return@withContext null - } - - val base64Job = async { - try { - accountsService.getAccountInfoMpl(accountsService.createAccountInfoRequest(metadataKey)) - .result.value.data.first() - } catch (_: Throwable) { - null - } - - } - val base64 = base64Job.await() ?: return@withContext null - - val metadata = try { - uniffi.gemstone.solanaDecodeMetadata(base64) - } catch (_: Throwable) { - return@withContext null - } - - Asset( - id = AssetId(chain = chain, tokenId = tokenId), - name = metadata.name, - symbol = metadata.symbol, - decimals = tokenInfo.decimals, - type = AssetType.SPL, - ) - } - - override suspend fun isTokenQuery(query: String): Boolean = isTokenAddress(query) - - override fun supported(chain: Chain): Boolean = this.chain == chain - - companion object { - fun isTokenAddress(tokenId: String): Boolean { - return tokenId.length in 40..60 && Base58.decodeNoCheck(tokenId)?.isNotEmpty() == true - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaTransactionStatusClient.kt deleted file mode 100644 index 504e8f02f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/SolanaTransactionStatusClient.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.solana.services.SolanaTransactionsService -import com.gemwallet.android.blockchain.clients.solana.services.transaction -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class SolanaTransactionStatusClient( - private val chain: Chain, - private val transactionService: SolanaTransactionsService, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val resp = transactionService.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - if (resp.error != null) return TransactionChanges(TransactionState.Failed) - val state = if (resp.result.slot > 0L) { - if (resp.result.meta.err != null) { - TransactionState.Failed - } else { - TransactionState.Confirmed - } - } else { - TransactionState.Pending - } - return TransactionChanges(state) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/models/SolanaParsed.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/models/SolanaParsed.kt deleted file mode 100644 index 82f863093..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/models/SolanaParsed.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.models - -class SolanaParsedData( - val data: SolanaParsed -) - -class SolanaParsed( - val parsed: T -) - -class SolanaInfo( - val info: T -) - -class SolanaParsedSplTokenInfo( - val decimals: Int, - val extensions: List? = null, -) - -class SolanaArrayData(val data: List) - -data class Extension ( - val extension: String, - val state: ExtensionState -) - -data class ExtensionState ( - val name: String?, - val symbol: String?, -) \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/models/SolanaTokenOwner.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/models/SolanaTokenOwner.kt deleted file mode 100644 index 955023de8..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/models/SolanaTokenOwner.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.models - -class SolanaTokenOwner(val owner: String) \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaAccountsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaAccountsService.kt deleted file mode 100644 index 1e35b672c..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaAccountsService.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.clients.solana.models.SolanaArrayData -import com.gemwallet.android.blockchain.clients.solana.models.SolanaInfo -import com.gemwallet.android.blockchain.clients.solana.models.SolanaParsedData -import com.gemwallet.android.blockchain.clients.solana.models.SolanaParsedSplTokenInfo -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaTokenAccount -import com.wallet.core.blockchain.solana.SolanaValue -import retrofit2.http.Body -import retrofit2.http.POST - -interface SolanaAccountsService { - @POST("/") - suspend fun getTokenAccountByOwner(@Body request: JSONRpcRequest>): JSONRpcResponse>> - - @POST("/") - suspend fun batchAccount(@Body request: List>>): List>>> - - @POST("/") - suspend fun getAccountInfoSpl(@Body request: JSONRpcRequest>): JSONRpcResponse>>> - - @POST("/") - suspend fun getAccountInfoMpl(@Body request: JSONRpcRequest>): JSONRpcResponse>> - - @POST("/") - suspend fun getTokenInfo(@Body request: JSONRpcRequest>): JSONRpcResponse> -} - -fun SolanaAccountsService.createAccountInfoRequest(tokenId: String): JSONRpcRequest> { - return JSONRpcRequest.create( - SolanaMethod.GetAccountInfo, - params = listOf( - tokenId, - mapOf( - "encoding" to "jsonParsed", - SolanaRpcClient.commitmentKey to SolanaRpcClient.commitmentValue, - ), - ) - ) -} - -fun SolanaAccountsService.createAccountByOwnerRequest(owner: String, tokenId: String): JSONRpcRequest> { - return JSONRpcRequest.create( - method = SolanaMethod.GetTokenAccountByOwner, - params = listOf( - owner, - mapOf("mint" to tokenId), - mapOf( - "encoding" to "jsonParsed", - SolanaRpcClient.commitmentKey to SolanaRpcClient.commitmentValue, - ), - ), - ) -} diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaBalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaBalancesService.kt deleted file mode 100644 index c91a911b4..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaBalancesService.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaBalance -import com.wallet.core.blockchain.solana.SolanaBalanceValue -import com.wallet.core.blockchain.solana.SolanaValue -import retrofit2.http.Body -import retrofit2.http.POST -import java.math.BigInteger - -interface SolanaBalancesService { - @POST("/") - suspend fun getBalance(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun getTokenBalance(@Body request: JSONRpcRequest>): Result>> -} - -suspend fun SolanaBalancesService.getBalance(address: String): Long? { - return getBalance( - JSONRpcRequest.create( - SolanaMethod.GetBalance, - listOf( - address, - mapOf(SolanaRpcClient.commitmentValue to SolanaRpcClient.commitmentValue) - ) - ) - ) - .getOrNull()?.result?.value -} - -suspend fun SolanaBalancesService.getTokenBalance(tokenAccount: String): BigInteger? { - val balanceRequest = JSONRpcRequest.create(SolanaMethod.GetTokenBalance, listOf(tokenAccount)) - return try { - getTokenBalance(balanceRequest).getOrNull()?.result?.value?.amount?.toBigInteger() - } catch (_: Throwable) { - null - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaBroadcastService.kt deleted file mode 100644 index e2156fe12..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaBroadcastService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import retrofit2.http.Body -import retrofit2.http.POST - -interface SolanaBroadcastService { - @POST("/") - suspend fun broadcast(@Body request: JSONRpcRequest>): Result> -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaFeeService.kt deleted file mode 100644 index e13a08fb6..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaFeeService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaPrioritizationFee -import retrofit2.http.Body -import retrofit2.http.POST - -interface SolanaFeeService { - @POST("/") - suspend fun getPriorityFees(@Body request: JSONRpcRequest>): Result>> -} - -suspend fun SolanaFeeService.getPriorityFees(): List { - val request = JSONRpcRequest.create(SolanaMethod.GetPriorityFee, listOf()) - return getPriorityFees(request).getOrNull()?.result ?: throw Exception("Can't load fee price") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaNetworkInfoService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaNetworkInfoService.kt deleted file mode 100644 index 7dca4fc0d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaNetworkInfoService.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaBlockhashResult -import retrofit2.http.Body -import retrofit2.http.POST - -interface SolanaNetworkInfoService { - - @POST("/") - suspend fun getBlockhash(@Body request: JSONRpcRequest>): Result> -} - -suspend fun SolanaNetworkInfoService.getBlockhash(): String { - val blockhash = getBlockhash(JSONRpcRequest.create(SolanaMethod.GetLatestBlockhash, emptyList())) - .getOrNull()?.result?.value?.blockhash - if (blockhash.isNullOrEmpty()) { - throw Exception("Can't get latest blockhash") - } - return blockhash -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaNodeStatusService.kt deleted file mode 100644 index 0e052a6e2..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaNodeStatusService.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST -import retrofit2.http.Url - -interface SolanaNodeStatusService { - - @POST - suspend fun health(@Url url: String,@Body request: JSONRpcRequest>): Response> - - @POST - suspend fun slot(@Url url: String, @Body request: JSONRpcRequest>): Result> - - @POST - suspend fun genesisHash(@Url url: String, @Body request: JSONRpcRequest>): Result> -} - -suspend fun SolanaNodeStatusService.health(url: String): Response> { - return health(url, JSONRpcRequest.create(SolanaMethod.GetHealth, emptyList())) -} - -suspend fun SolanaNodeStatusService.slot(url: String): Result> { - return slot(url, JSONRpcRequest.create(SolanaMethod.GetSlot, emptyList())) -} - -suspend fun SolanaNodeStatusService.genesisHash(url: String): Result> { - return genesisHash(url, JSONRpcRequest.create(SolanaMethod.GetGenesisHash, emptyList())) -} diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaRpcClient.kt deleted file mode 100644 index becad2507..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaRpcClient.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -interface SolanaRpcClient : - SolanaAccountsService, - SolanaBalancesService, - SolanaStakeService, - SolanaFeeService, - SolanaNetworkInfoService, - SolanaBroadcastService, - SolanaTransactionsService, - SolanaNodeStatusService { - - companion object { - val commitmentKey: String = "commitment" - val commitmentValue: String = "confirmed" - } -} diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaStakeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaStakeService.kt deleted file mode 100644 index dce95a4df..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaStakeService.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaEpoch -import com.wallet.core.blockchain.solana.SolanaStakeAccount -import com.wallet.core.blockchain.solana.SolanaValidator -import com.wallet.core.blockchain.solana.SolanaValidators -import retrofit2.http.Body -import retrofit2.http.POST - -interface SolanaStakeService { - @POST("/") - suspend fun validators(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun delegations(@Body request: JSONRpcRequest>): Result>> - - @POST("/") - suspend fun epoch(@Body request: JSONRpcRequest>): Result> -} - -suspend fun SolanaStakeService.delegations( - owner: String, -): List? { - val request = JSONRpcRequest.create( - SolanaMethod.GetDelegations, - listOf( - "Stake11111111111111111111111111111111111111", - mapOf( - "encoding" to "jsonParsed", - SolanaRpcClient.commitmentKey to SolanaRpcClient.commitmentValue, - "filters" to listOf( - mapOf( - "memcmp" to mapOf( - "bytes" to owner, - "offset" to 44, - ) - ) - ) - ) - ) - ) - return delegations(request).getOrNull()?.result -} - -suspend fun SolanaStakeService.getDelegationsBalance(owner: String): Long { - return delegations(owner)?.map { it.account.lamports }?.fold(0L) { acc, v -> acc + v } ?: 0L -} - -suspend fun SolanaStakeService.validators(): List? { - val request = JSONRpcRequest.create( - SolanaMethod.GetValidators, - listOf( - mapOf( - SolanaRpcClient.commitmentKey to SolanaRpcClient.commitmentValue, - "keepUnstakedDelinquents" to false - ) - ) - ) - return validators(request).getOrNull()?.result?.current -} - -suspend fun SolanaStakeService.epoch(): SolanaEpoch? { - return epoch(JSONRpcRequest.create(SolanaMethod.GetEpoch, emptyList())).getOrNull()?.result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaTransactionsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaTransactionsService.kt deleted file mode 100644 index 57c8b0a26..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/solana/services/SolanaTransactionsService.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.gemwallet.android.blockchain.clients.solana.services - -import com.gemwallet.android.blockchain.clients.solana.SolanaMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.solana.SolanaTransaction -import retrofit2.http.Body -import retrofit2.http.POST - -interface SolanaTransactionsService { - @POST("/") - suspend fun transaction(@Body request: JSONRpcRequest>): Result> -} - -suspend fun SolanaTransactionsService.transaction(hash: String): Result> { - val request = JSONRpcRequest.create( - SolanaMethod.GetTransaction, - listOf( - hash, - mapOf( - "encoding" to "jsonParsed", - SolanaRpcClient.commitmentKey to SolanaRpcClient.commitmentValue, - "maxSupportedTransactionVersion" to 0, - ), - ) - ) - return transaction(request) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarBalanceClient.kt deleted file mode 100644 index f010db09d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarBalanceClient.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.stellar.services.StellarAccountService -import com.gemwallet.android.blockchain.clients.stellar.services.accounts -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.getReserveBalance -import com.gemwallet.android.model.AssetBalance -import com.gemwallet.android.model.Crypto -import com.wallet.core.primitives.Chain - -class StellarBalanceClient( - private val chain: Chain, - private val accountService: StellarAccountService, -) : BalanceClient { - - override suspend fun getNativeBalance( - chain: Chain, - address: String - ): AssetBalance? { - val reserved = chain.getReserveBalance() - val balance = try { - val result = accountService.accounts(address)?.balances - ?.firstOrNull { it.asset_type == "native" }?.balance ?: return null - val value = Crypto(result, chain.asset().decimals).atomicValue - (value - reserved).max(reserved) - } catch (_: Throwable) { - return null - } - return AssetBalance.create(chain.asset(), available = balance.toString(), reserved = reserved.toString()) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarBroadcastClient.kt deleted file mode 100644 index c0478ab8f..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarBroadcastClient.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.stellar.services.StellarBroadcastService -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.blockchain.rpc.responseFold -import com.wallet.core.blockchain.stellar.StellarTransactionBroadcast -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import okhttp3.RequestBody.Companion.toRequestBody -import java.net.URLEncoder - -class StellarBroadcastClient( - private val chain: Chain, - private val broadcastService: StellarBroadcastService -) : BroadcastClient { - - override suspend fun send( - account: Account, - signedMessage: ByteArray, - type: TransactionType - ): String { - val encoded = "tx=${URLEncoder.encode(String(signedMessage), "utf-8")}" - val resp = broadcastService.broadcast(encoded.toRequestBody(Mime.Form.value)) - - return resp.responseFold( - onSuccess = { - it?.hash ?: throw ServiceError.EmptyHash - }, - onError = { err: StellarTransactionBroadcast -> - throw Exception(err.title) - }, - onFailure = { cause -> - val error = cause.message?.let { ServiceError.BroadCastError(it) } - ?: ServiceError.ServerError(err = cause) - throw error - } - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} - diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarChainData.kt new file mode 100644 index 000000000..82eebfdfe --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarChainData.kt @@ -0,0 +1,16 @@ +package com.gemwallet.android.blockchain.clients.stellar + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class StellarChainData( + val sequence: ULong, + val isDestinationAddressExist: Boolean, +) : ChainSignData + +fun GemTransactionLoadMetadata.Stellar.toChainData(): StellarChainData { + return StellarChainData( + sequence = sequence, + isDestinationAddressExist = isDestinationAddressExist, + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarFeeCalculator.kt deleted file mode 100644 index 83aa26c36..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarFeeCalculator.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar - -import com.gemwallet.android.blockchain.clients.stellar.services.StellarFeeService -import com.gemwallet.android.model.Fee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import java.math.BigInteger - -class StellarFeeCalculator( - private val chain: Chain, - private val feeService: StellarFeeService, -) { - suspend fun calculate(): List { - val fees = feeService.fee().getOrNull() ?: throw Exception("fee load error") - val min = BigInteger(fees.fee_charged.min).max(BigInteger(fees.last_ledger_base_fee)) - val assetId = AssetId(chain) - return listOf( - Fee( - priority = FeePriority.Slow, - feeAssetId = assetId, - amount = min, - ), - Fee( - priority = FeePriority.Normal, - feeAssetId = assetId, - amount = min, - ), - Fee( - priority = FeePriority.Fast, - feeAssetId = assetId, - amount = BigInteger(fees.fee_charged.p95) * BigInteger("2"), - ), - ) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarNodeStatusClient.kt deleted file mode 100644 index 1779ad028..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarNodeStatusClient.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.clients.stellar.services.StellarNodeStatusService -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain - -class StellarNodeStatusClient( - private val chain: Chain, - private val nodeStatusService: StellarNodeStatusService, -) : NodeStatusClient { - - override suspend fun getNodeStatus( - chain: Chain, - url: String - ): NodeStatus? { - val resp = nodeStatusService.node("$url") - val result = resp.body() - return NodeStatus( - url = url, - blockNumber = result?.ingest_latest_ledger?.toString() ?: return null, - inSync = true, - chainId = result.network_passphrase, - latency = resp.getLatency() - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignClient.kt index 4128c3c8c..5f9270325 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignClient.kt @@ -4,9 +4,10 @@ import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority +import uniffi.gemstone.GemFeeOption import wallet.core.java.AnySigner import wallet.core.jni.StellarPassphrase import wallet.core.jni.proto.Stellar @@ -20,22 +21,22 @@ class StellarSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = (chainData as? StellarSignPreloadClient.StellarChainData) + val chainData = (chainData as? StellarChainData) ?: throw Exception("bad params") val input = Stellar.SigningInput.newBuilder().apply { this.passphrase = StellarPassphrase.STELLAR.toString() - this.fee = chainData.fee(feePriority).amount.toInt() - this.sequence = chainData.sequence + this.fee = fee.amount.toInt() + this.sequence = chainData.sequence.toLong() this.account = params.from.address if (!params.memo().isNullOrEmpty()) { this.memoText = Stellar.MemoText.newBuilder().apply { this.text = params.memo()!! }.build() } - if (chainData.fee(feePriority).options.contains(StellarSignPreloadClient.StellarChainData.tokenAccountCreation)) { + if (fee.options.contains(GemFeeOption.TOKEN_ACCOUNT_CREATION.name)) { this.opCreateAccount = Stellar.OperationCreateAccount.newBuilder().apply { this.destination = params.destination().address this.amount = finalAmount.toLong() diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignPreloadClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignPreloadClient.kt deleted file mode 100644 index 1310888e9..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarSignPreloadClient.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.stellar.services.StellarAccountService -import com.gemwallet.android.blockchain.clients.stellar.services.StellarFeeService -import com.gemwallet.android.blockchain.clients.stellar.services.accounts -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class StellarSignPreloadClient( - private val chain: Chain, - private val accountService: StellarAccountService, - feeService: StellarFeeService, -) : NativeTransferPreloader { - - private val feeCalculator = StellarFeeCalculator(chain, feeService) - - override suspend fun preloadNativeTransfer( - params: ConfirmParams.TransferParams.Native - ): SignerParams = withContext(Dispatchers.IO) { - val getAccount = async { accountService.accounts(params.from.address) } - val getIsDestinationAccountExist = async { - try { - accountService.accounts(params.destination.address) != null - } catch (_: Throwable) { - false - } - } - val getDefaultFees = async { feeCalculator.calculate() } - - val account = getAccount.await() - val isDestinationAccountExist = getIsDestinationAccountExist.await() - val defaultFees = getDefaultFees.await() - - if (account?.sequence == null) { - throw Exception("invalid sequence") - } - val fees = if (isDestinationAccountExist) { - defaultFees - } else { - defaultFees.map { - Fee( - priority = it.priority, - feeAssetId = it.feeAssetId, - amount = it.amount, - options = mapOf(StellarChainData.tokenAccountCreation to BigInteger.ZERO) - ) - } - } - SignerParams( - input = params, - chainData = StellarChainData( - fees = fees, - sequence = account.sequence.toLong() + 1 - ) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class StellarChainData( - val fees: List, - val sequence: Long, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fees.firstOrNull { it.priority == speed } ?: fees.first() - - override fun allFee(): List = fees - - companion object { - const val tokenAccountCreation = "tokenAccountCreation" - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarTransactionStatusClient.kt deleted file mode 100644 index 4e2f4c9be..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/StellarTransactionStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.blockchain.clients.stellar.services.StellarTxStatusService -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class StellarTransactionStatusClient( - private val chain: Chain, - private val txStatusService: StellarTxStatusService, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val tx = txStatusService.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - val state = if (tx.successful == true) TransactionState.Confirmed else TransactionState.Failed - return TransactionChanges( - state = state, - fee = try { tx.fee_charged.toBigInteger() } catch (_: Throwable) { null } - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarAccountService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarAccountService.kt deleted file mode 100644 index c2b6b764b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarAccountService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar.services - -import com.wallet.core.blockchain.stellar.StellarAccount -import retrofit2.http.GET -import retrofit2.http.Path - -interface StellarAccountService { - @GET("/accounts/{address}") - suspend fun loadAccounts(@Path("address") address: String): Result -} - -suspend fun StellarAccountService.accounts(address: String): StellarAccount? { - val result = loadAccounts(address) - - return result.getOrNull() -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarBroadcastService.kt deleted file mode 100644 index d8f8daaca..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarBroadcastService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar.services - -import com.wallet.core.blockchain.stellar.StellarTransactionBroadcast -import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.POST - -interface StellarBroadcastService { - @POST("/transactions") - suspend fun broadcast(@Body body: RequestBody): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarFeeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarFeeService.kt deleted file mode 100644 index bd6d6d967..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarFeeService.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar.services - -import com.wallet.core.blockchain.stellar.StellarFees -import retrofit2.http.GET - -interface StellarFeeService { - @GET("/fee_stats") - suspend fun fee(): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarNodeStatusService.kt deleted file mode 100644 index ab6072a44..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarNodeStatusService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar.services - -import com.wallet.core.blockchain.stellar.StellarNodeStatus -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.Url - -interface StellarNodeStatusService { - @GET//("/") - suspend fun node(@Url url: String): Response -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarService.kt deleted file mode 100644 index 3fa24ff30..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarService.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar.services - -interface StellarService : StellarAccountService, - StellarBroadcastService, - StellarFeeService, - StellarTxStatusService, - StellarNodeStatusService \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarTxStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarTxStatusService.kt deleted file mode 100644 index 33b50f6b8..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/stellar/services/StellarTxStatusService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.gemwallet.android.blockchain.clients.stellar.services - -import com.wallet.core.blockchain.stellar.StellarTransactionStatus -import retrofit2.http.GET -import retrofit2.http.Path - -interface StellarTxStatusService { - @GET("/transactions/{id}") - suspend fun transaction(@Path("id") id: String): Result -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiBalanceClient.kt deleted file mode 100644 index c350f58fe..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiBalanceClient.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.total -import com.gemwallet.android.math.clean0xPrefix -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.blockchain.sui.SuiCoinBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import java.math.BigInteger - -class SuiBalanceClient( - private val chain: Chain, - private val rpcClient: SuiRpcClient, -) : BalanceClient { - override fun supported(chain: Chain): Boolean = this.chain == chain - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - val amount = rpcClient.balance(address) - .mapCatching { it.result.totalBalance.toBigInteger() } - .getOrNull() ?: return null - return AssetBalance.create(chain.asset(), available = amount.toString()) - } - - override suspend fun getDelegationBalances(chain: Chain, address: String): AssetBalance? { - val delegations = rpcClient.delegations(JSONRpcRequest.create(SuiMethod.Delegations, listOf(address))) - .getOrNull()?.result ?: emptyList() - - val staked = delegations.map { - it.stakes.map { stake -> stake.total() }.fold(BigInteger.ZERO) { acc, value -> acc + value} - }.fold(BigInteger.ZERO) {acc, value -> acc + value} - - return AssetBalance.create(chain.asset(), staked = staked.toString()) - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - return rpcClient.balances(address).mapCatching { response -> - val balances = response.result - tokens.mapNotNull { token -> - AssetBalance.create( - token, - balances.firstOrNull { it.isCoinType(token.id.tokenId) }?.totalBalance ?: return@mapNotNull null, - ) - } - }.getOrNull() ?: emptyList() - } - - fun SuiCoinBalance.isCoinType(tokenId: String?): Boolean { - return coinType.clean0xPrefix() == tokenId?.clean0xPrefix()?.removePrefix("0") - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiBroadcastClient.kt deleted file mode 100644 index d74f913ec..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiBroadcastClient.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class SuiBroadcastClient( - private val chain: Chain, - private val rpcClient: SuiRpcClient, -) : BroadcastClient { - - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val parts = String(signedMessage).split("_") - val data = parts.first() - val sign = parts[1] - return rpcClient.broadcast(data, sign).getOrNull()?.result?.digest ?: throw ServiceError.NetworkError - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiChainData.kt new file mode 100644 index 000000000..67119a30a --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiChainData.kt @@ -0,0 +1,14 @@ +package com.gemwallet.android.blockchain.clients.sui + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class SuiChainData( + val messageBytes: String, +) : ChainSignData + +fun GemTransactionLoadMetadata.Sui.toChainData(): SuiChainData { + return SuiChainData( + messageBytes = messageBytes, + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiFeeCalculator.kt deleted file mode 100644 index d7fe6fb73..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiFeeCalculator.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.model.Fee -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.FeePriority - -class SuiFeeCalculator( - private val rpcClient: SuiRpcClient, -) { - suspend fun calculate(account: Account, data: String): Fee { - val chain = account.chain - val gasUsed = rpcClient.dryRun(data) - val computationCost = gasUsed.computationCost.toBigInteger() - val storageCost = gasUsed.storageCost.toBigInteger() - val storageRebate = gasUsed.storageRebate.toBigInteger() - val fee = computationCost.max(computationCost + storageCost - storageRebate) - return Fee(feeAssetId = AssetId(chain), priority = FeePriority.Normal, amount = fee.abs()) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiGetTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiGetTokenClient.kt deleted file mode 100644 index 9e43a6aef..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiGetTokenClient.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.GetTokenClient -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain - -class SuiGetTokenClient( - private val chain: Chain, - private val rpcClient: SuiRpcClient, -) : GetTokenClient { - override suspend fun getTokenData(tokenId: String): Asset? { - val metadata = rpcClient.getCoinMetadata(JSONRpcRequest.create(SuiMethod.CoinMetadata, listOf(tokenId))) - .getOrNull() - val result = if (metadata?.result == null) { - return null - } else { - metadata.result - } - return Asset( - id = AssetId(chain, tokenId), - name = result.name, - symbol = result.symbol, - decimals = result.decimals, - type = AssetType.TOKEN, - ) - } - - override suspend fun isTokenQuery(query: String): Boolean = isTokenAddress(query) - - override fun supported(chain: Chain): Boolean = this.chain == chain - - companion object { - fun isTokenAddress(tokenId: String): Boolean { - return tokenId.startsWith("0x") && tokenId.length in 66..100 - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiMethod.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiMethod.kt deleted file mode 100644 index 7ba757d3b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiMethod.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcMethod - -enum class SuiMethod(val value: String) : JSONRpcMethod { - Coins("suix_getCoins"), - Balance("suix_getBalance"), - Balances("suix_getAllBalances"), - GasPrice("suix_getReferenceGasPrice"), - Pay("unsafe_pay"), - PaySui("unsafe_paySui"), - PayAllSui("unsafe_payAllSui"), - DryRun("sui_dryRunTransactionBlock"), - Transaction("sui_getTransactionBlock"), - Broadcast("sui_executeTransactionBlock"), - Validators("suix_getValidatorsApy"), - Delegations("suix_getStakes"), - GetObject("sui_getObject"), - CoinMetadata("suix_getCoinMetadata"), - SystemState("suix_getLatestSuiSystemState"), - ChainId("sui_getChainIdentifier"), - LatestCheckpoint("sui_getLatestCheckpointSequenceNumber"), - ; - - override fun value(): String = value -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiNodeStatusClient.kt deleted file mode 100644 index 71776be2e..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiNodeStatusClient.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class SuiNodeStatusClient( - private val chain: Chain, - private val rpcClient: SuiRpcClient, -) : NodeStatusClient { - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val chainIdJob = async { rpcClient.chainId(url) } - val blockJob = async { rpcClient.latestBlock(url).getOrNull() } - - val chainIdResp = chainIdJob.await() - val block = blockJob.await() - val chainId = chainIdResp.body()?.result - - NodeStatus( - url = url, - inSync = true, - blockNumber = block?.result?.toString() ?: return@withContext null, - chainId = chainId ?: return@withContext null, - latency = chainIdResp.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiRpcClient.kt deleted file mode 100644 index ff6d3219b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiRpcClient.kt +++ /dev/null @@ -1,121 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.sui.model.SuiObject -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.blockchain.rpc.model.JSONRpcResponse -import com.wallet.core.blockchain.sui.SuiBroadcastTransaction -import com.wallet.core.blockchain.sui.SuiCoin -import com.wallet.core.blockchain.sui.SuiCoinBalance -import com.wallet.core.blockchain.sui.SuiCoinMetadata -import com.wallet.core.blockchain.sui.SuiData -import com.wallet.core.blockchain.sui.SuiGasUsed -import com.wallet.core.blockchain.sui.SuiStakeDelegation -import com.wallet.core.blockchain.sui.SuiSystemState -import com.wallet.core.blockchain.sui.SuiTransaction -import com.wallet.core.blockchain.sui.SuiValidators -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST -import retrofit2.http.Url - -interface SuiRpcClient { - - @POST("/") - suspend fun coins(@Body request: JSONRpcRequest>): Result>>> - - @POST("/") - suspend fun balance(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun balances(@Body request: JSONRpcRequest>): Result>> - - @POST("/") - suspend fun gasPrice(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun dryRun(@Body request: JSONRpcRequest>):Result> - - @POST("/") - suspend fun transaction(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun broadcast(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun validators(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun delegations(@Body request: JSONRpcRequest>): Result>> - - @POST("/") - suspend fun getObject(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun getCoinMetadata(@Body request: JSONRpcRequest>): Result> - - @POST("/") - suspend fun systemState(@Body request: JSONRpcRequest>): Result> - - @POST - suspend fun chainId(@Url url: String, @Body request: JSONRpcRequest>): Response> - - @POST - suspend fun latestBlock(@Url url: String, @Body request: JSONRpcRequest>): Result> -} - -internal suspend fun SuiRpcClient.coins(address: String, coinType: String): Result>>> { - return coins(JSONRpcRequest.create(SuiMethod.Coins, listOf(address, coinType))) -} - -internal suspend fun SuiRpcClient.balance(address: String): Result> { - return balance(JSONRpcRequest.create(SuiMethod.Balance, listOf(address))) -} - -internal suspend fun SuiRpcClient.balances(address: String): Result>> { - return balances(JSONRpcRequest.create(SuiMethod.Balances, listOf(address))) -} - -internal suspend fun SuiRpcClient.broadcast(data: String, sign: String): Result> { - val request = JSONRpcRequest.create( - SuiMethod.Broadcast, - listOf( - data, - listOf(sign), - null, - "WaitForLocalExecution", - ) - ) - return broadcast(request) -} - -internal suspend fun SuiRpcClient.transaction(txId: String): Result> { - val request = JSONRpcRequest.create( - SuiMethod.Transaction, - listOf( - txId, - mapOf("showEffects" to true) - ) - ) - return transaction(request) -} - -internal suspend fun SuiRpcClient.systemState(): Result> { - val request = JSONRpcRequest.create( - SuiMethod.SystemState, - emptyList(), - ) - return systemState(request) -} - -internal suspend fun SuiRpcClient.chainId(url: String): Response> { - return chainId(url, JSONRpcRequest.create(SuiMethod.ChainId, emptyList())) -} - -internal suspend fun SuiRpcClient.latestBlock(url: String): Result> { - return latestBlock(url, JSONRpcRequest.create(SuiMethod.LatestCheckpoint, emptyList())) -} - -internal suspend fun SuiRpcClient.dryRun(data: String): SuiGasUsed { - return dryRun(JSONRpcRequest.create(SuiMethod.DryRun, listOf(data))).getOrNull()?.result?.effects?.gasUsed - ?: throw Exception("Can't load SUI gas") -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignClient.kt index 239a74396..426f6f082 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignClient.kt @@ -4,8 +4,8 @@ import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.math.decodeHex import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.jni.Base64 import wallet.core.jni.Curve import wallet.core.jni.PrivateKey @@ -19,10 +19,10 @@ class SuiSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val metadata = chainData as SuiSignerPreloader.SuiChainData + val metadata = chainData as SuiChainData return signTxDataDigest(metadata.messageBytes, privateKey) } @@ -30,10 +30,10 @@ class SuiSignClient( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val metadata = chainData as SuiSignerPreloader.SuiChainData + val metadata = chainData as SuiChainData return signTxDataDigest(metadata.messageBytes, privateKey) } @@ -41,10 +41,10 @@ class SuiSignClient( params: ConfirmParams.Stake.DelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val metadata = chainData as SuiSignerPreloader.SuiChainData + val metadata = chainData as SuiChainData return signTxDataDigest(metadata.messageBytes, privateKey) } @@ -52,10 +52,10 @@ class SuiSignClient( params: ConfirmParams.Stake.UndelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val metadata = chainData as SuiSignerPreloader.SuiChainData + val metadata = chainData as SuiChainData return signTxDataDigest(metadata.messageBytes, privateKey) } @@ -63,10 +63,10 @@ class SuiSignClient( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val metadata = chainData as SuiSignerPreloader.SuiChainData + val metadata = chainData as SuiChainData return signTxDataDigest(metadata.messageBytes, privateKey) } diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignerPreloader.kt deleted file mode 100644 index 9c9a21cdb..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiSignerPreloader.kt +++ /dev/null @@ -1,200 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import uniffi.gemstone.SuiCoin -import uniffi.gemstone.SuiGas -import uniffi.gemstone.SuiObjectRef -import uniffi.gemstone.SuiStakeInput -import uniffi.gemstone.SuiTokenTransferInput -import uniffi.gemstone.SuiTransferInput -import uniffi.gemstone.SuiTxOutput -import uniffi.gemstone.SuiUnstakeInput -import uniffi.gemstone.suiEncodeSplitStake -import uniffi.gemstone.suiEncodeTokenTransfer -import uniffi.gemstone.suiEncodeTransfer -import uniffi.gemstone.suiEncodeUnstake -import uniffi.gemstone.suiValidateAndHash -import wallet.core.jni.Base64 -import java.math.BigInteger - -class SuiSignerPreloader( - private val chain: Chain, - private val rpcClient: SuiRpcClient, -) : NativeTransferPreloader, TokenTransferPreloader, StakeTransactionPreloader, SwapTransactionPreloader { - - private val feeCalculator = SuiFeeCalculator(rpcClient) - - private val coinId = "0x2::sui::SUI" - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams = withContext(Dispatchers.IO) { - val sender = params.from.address - val getCoins = async { rpcClient.coins(sender, coinId).getOrThrow().result.data } - val getGasPrice = async { rpcClient.gasPrice(JSONRpcRequest.create(SuiMethod.GasPrice, emptyList())).getOrNull()?.result ?: "750" } - val coins = getCoins.await() - val gasPrice = getGasPrice.await() - val input = SuiTransferInput( - sender = sender, - recipient = params.destination.address, - amount = params.amount.toLong().toULong(), - coins = coins.map { it.togemstone() }, - sendMax = params.isMax(), - gas = SuiGas( - budget = gasBudget(coinId).toLong().toULong(), - price = gasPrice.toULong(), - ) - ) - val data = suiEncodeTransfer(input) - build(params, data) - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams = withContext(Dispatchers.IO) { - val sender = params.from.address - val getCoins = async { - rpcClient.coins(sender, params.assetId.tokenId!!).getOrThrow().result.data - } - val getGasCoins = async { - rpcClient.coins(sender, coinId).getOrThrow().result.data - } - val getGasPrice = async { rpcClient.gasPrice(JSONRpcRequest.create(SuiMethod.GasPrice, emptyList())).getOrNull()?.result ?: "750" } - val coins = getCoins.await() - val gasPrice = getGasPrice.await() - val gasCoins = getGasCoins.await() - val gas = gasCoins.firstOrNull() ?: throw IllegalStateException("no gas coin") - val input = SuiTokenTransferInput( - sender = sender, - recipient = params.destination.address, - amount = params.amount.toLong().toULong(), - tokens = coins.map { it.togemstone() }, - gas = SuiGas( - budget = gasBudget(coinId).toLong().toULong(), - price = gasPrice.toULong(), - ), - gasCoin = gas.togemstone(), - ) - val data = suiEncodeTokenTransfer(input) - build(params, data) - } - - override suspend fun preloadStake(params: ConfirmParams.Stake): SignerParams { - val data = when (params) { - is ConfirmParams.Stake.DelegateParams -> encodeStake( - sender = params.from.address, - validator = params.validatorId, - coinType = coinId, - value = params.amount, - ) - is ConfirmParams.Stake.UndelegateParams -> encodeUnstake( - sender = params.from.address, - coinType = coinId, - stakeId = params.delegationId, - ) - is ConfirmParams.Stake.RewardsParams, - is ConfirmParams.Stake.RedelegateParams, - is ConfirmParams.Stake.WithdrawParams -> throw IllegalArgumentException("Not supported") - } - return build(params, data) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - val data = suiValidateAndHash(params.swapData) - return build(params, data) - } - - private suspend fun build(params: ConfirmParams, data: SuiTxOutput): SignerParams { - val fee = feeCalculator.calculate(params.from, Base64.encode(data.txData)) - - return SignerParams( - input = params, - chainData = SuiChainData( - messageBytes = "${Base64.encode(data.txData)}_${data.hash.toHexString()}", - fee = fee, - ) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private fun gasBudget(coinType: String): BigInteger = BigInteger.valueOf(25_000_000) - - private suspend fun encodeStake( - sender: String, - coinType: String, - value: BigInteger, - validator: String, - ) = withContext(Dispatchers.IO) { - val getCoins = async { rpcClient.coins(sender, coinType).getOrThrow().result.data } - val getGasPrice = async { rpcClient.gasPrice(JSONRpcRequest.create(SuiMethod.GasPrice, emptyList())).getOrNull()?.result ?: "750" } - val coins = getCoins.await() - val gasPrice = getGasPrice.await() - val input = SuiStakeInput( - sender = sender, - validator = validator, - stakeAmount = value.toLong().toULong(), - coins = coins.map { it.togemstone() }, - gas = SuiGas( - budget = gasBudget(coinType).toLong().toULong(), - price = gasPrice.toULong(), - ) - ) - suiEncodeSplitStake(input) - } - - private suspend fun encodeUnstake( - sender: String, - coinType: String, - stakeId: String, - ) = withContext(Dispatchers.IO) { - val getCoins = async { rpcClient.coins(sender, coinType).getOrThrow().result.data } - val getGasPrice = async { rpcClient.gasPrice(JSONRpcRequest.create(SuiMethod.GasPrice, emptyList())).getOrNull()?.result ?: "750" } - val getObject = async { rpcClient.getObject(JSONRpcRequest.create(SuiMethod.GetObject, listOf(stakeId))).getOrNull()?.result ?: throw IllegalStateException() } - val coins = getCoins.await() - val gasPrice = getGasPrice.await() - val suiObject = getObject.await() - - val input = SuiUnstakeInput( - sender = sender, - stakedSui = SuiObjectRef( - objectId = suiObject.data.objectId, - digest = suiObject.data.digest, - version = suiObject.data.version.toULong(), - ), - gasCoin = coins.map { it.togemstone() }.first(), - gas = SuiGas( - budget = gasBudget(coinType).toLong().toULong(), - price = gasPrice.toULong(), - ) - ) - suiEncodeUnstake(input) - } - - data class SuiChainData( - val messageBytes: String, - val fee: Fee, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - } - - private fun com.wallet.core.blockchain.sui.SuiCoin.togemstone() = SuiCoin( - coinType = coinType, - balance = balance.toULong(), - objectRef = SuiObjectRef( - objectId = coinObjectId, - digest = digest, - version = version.toULong(), - ) - ) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiStakeClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiStakeClient.kt deleted file mode 100644 index 7a759480b..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiStakeClient.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.StakeClient -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.gemwallet.android.ext.asset -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationState -import com.wallet.core.primitives.DelegationValidator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class SuiStakeClient( - private val chain: Chain, - private val rpcClient: SuiRpcClient -): StakeClient { - override suspend fun getValidators(chain: Chain, apr: Double): List { - val validators = rpcClient.validators(JSONRpcRequest.create(SuiMethod.Validators, listOf())) - .getOrNull()?.result?.apys ?: return emptyList() - return validators.map { - DelegationValidator( - chain = chain, - id = it.address, - name = "", - isActive = true, - commision = 0.0, - apr = apr, - ) - - } - } - - override suspend fun getStakeDelegations(chain: Chain, address: String, apr: Double): List = withContext(Dispatchers.IO) { - val getDelegations = async { - rpcClient.delegations(JSONRpcRequest.create(SuiMethod.Delegations, listOf(address))) - .getOrNull()?.result - } - val getSystemState = async { rpcClient.systemState().getOrNull() } - - val delegations = getDelegations.await() ?: return@withContext emptyList() - val systemState = getSystemState.await() ?: return@withContext emptyList() - val nextEpoch = (systemState.result.epochStartTimestampMs.toLongOrNull() ?: 0L) + - (systemState.result.epochDurationMs.toLongOrNull() ?: 0L) - - delegations.map { delegation -> - delegation.stakes.map { stake -> - val state = when (stake.status) { - "Active" -> DelegationState.Active - "Pending" -> DelegationState.Activating - else -> DelegationState.Pending - } - - DelegationBase( - assetId = chain.asset().id, - state = state, - rewards = stake.estimatedReward ?: "0", - delegationId = stake.stakedSuiId, - validatorId = delegation.validatorAddress, - balance = stake.principal, - completionDate = nextEpoch, - shares = "", - ) - } - }.flatten() - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiTransactionStatusClient.kt deleted file mode 100644 index c0d34a8ff..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/SuiTransactionStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class SuiTransactionStatusClient( - private val chain: Chain, - private val rpcClient: SuiRpcClient, -) : TransactionStatusClient { - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val resp = rpcClient.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - return TransactionChanges( - when (resp.result.effects.status.status) { - "success" -> TransactionState.Confirmed - "failure" -> TransactionState.Reverted - else -> TransactionState.Pending - } - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/model/SuiObject.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/model/SuiObject.kt deleted file mode 100644 index 1e04a7405..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/sui/model/SuiObject.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.sui.model - -import kotlinx.serialization.Serializable - -@Serializable -data class SuiObject( - val data: Data, -) { - @Serializable - data class Data( - val objectId: String, - val version: String, - val digest: String, - ) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonBalanceClient.kt deleted file mode 100644 index 0274cbf46..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonBalanceClient.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import java.math.BigInteger - -class TonBalanceClient( - private val chain: Chain, - private val rpcClient: TonRpcClient, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - return rpcClient.balance(address) - .fold( { AssetBalance.create(chain.asset(), it.result) } ) { null } - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - val jettonWallets = rpcClient.getJettonWallets(address) - return jettonWallets.jetton_wallets.mapNotNull { wallet -> - val jettonTokenId = uniffi.gemstone.tonHexToBase64Address(wallet.jetton) - val tokenAsset = tokens.firstOrNull { it.id.tokenId == jettonTokenId } ?: return@mapNotNull null - AssetBalance.create(tokenAsset, available = wallet.balance) - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private suspend fun tokenBalance(jettonAddress: String): BigInteger { - return BigInteger.valueOf( - rpcClient.tokenBalance(jettonAddress).getOrNull()?.result?.balance ?: 0L - ) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonBroadcastClient.kt deleted file mode 100644 index 6bb2b5c5a..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonBroadcastClient.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.blockchain.rpc.ServiceError.EmptyHash -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import wallet.core.jni.Base64 -import java.nio.charset.StandardCharsets - -class TonBroadcastClient( - private val chain: Chain, - private val rpcClient: TonRpcClient, -) : BroadcastClient { - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val encodedMessage = signedMessage.toString(StandardCharsets.UTF_8) - val response = rpcClient.broadcast(TonRpcClient.Boc(encodedMessage)).getOrNull() - ?: throw ServiceError.NetworkError - val hash = try { - Base64.decode(response.result.hash).toHexString("") - } catch (_: Throwable) { - throw EmptyHash - } - return hash - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonChainData.kt new file mode 100644 index 000000000..36a1f04e0 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonChainData.kt @@ -0,0 +1,17 @@ +package com.gemwallet.android.blockchain.clients.ton + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class TonChainData( + val sequence: ULong, + val jettonAddress: String? = null, + val expireAt: Int? = null +) : ChainSignData + +fun GemTransactionLoadMetadata.Ton.toChainData(): TonChainData { + return TonChainData( + sequence = sequence, + jettonAddress = recipientTokenAddress, + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonFeeCalculator.kt deleted file mode 100644 index b9d4b5376..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonFeeCalculator.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.model.Fee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class TonFeeCalculator( - private val chain: Chain, - private val rpcClient: TonRpcClient, -) { - val baseFee = BigInteger.valueOf(10_000_000L) - val jettonTokenAccountCreation = BigInteger.valueOf(300_000_000L) - - fun calculateNative() = Fee(FeePriority.Normal, AssetId(chain), baseFee) - - suspend fun calculateToken(assetId: AssetId, destinationAddress: String, memo: String?): Fee = withContext(Dispatchers.IO) { - val tokenId = assetId.tokenId!! - val hexTokenId = uniffi.gemstone.tonBase64ToHexAddress(tokenId) - val jetonAddress = rpcClient.getJettonWallets(destinationAddress) - .jetton_wallets.firstOrNull { it.jetton == hexTokenId }?.address - - val state = jetonAddress?.let { true } ?: false - val tokenAccountFee = if (state) { - if (memo.isNullOrEmpty()) { - BigInteger.valueOf(100_000_000) - } else { - BigInteger.valueOf(60_000_000) // 0.06 - } - } else { - jettonTokenAccountCreation - } - Fee( - FeePriority.Normal, - AssetId(assetId.chain), - baseFee, - options = mapOf(tokenAccountCreationKey to tokenAccountFee) - ).withOptions(tokenAccountCreationKey) - } - - fun calculateSwap(): Fee { -// val fee = baseFee + jettonTokenAccountCreation - return Fee( - FeePriority.Normal, - AssetId(chain), - baseFee, - options = mapOf(tokenAccountCreationKey to jettonTokenAccountCreation) - ).withOptions(tokenAccountCreationKey) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonGetTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonGetTokenClient.kt deleted file mode 100644 index 1021703ad..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonGetTokenClient.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.blockchain.clients.GetTokenClient -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain - -class TonGetTokenClient( - val chain: Chain, - val rpcClient: TonRpcClient, -) : GetTokenClient { - override suspend fun getTokenData(tokenId: String): Asset? { - val data = rpcClient.tokenData(tokenId).getOrNull()?.result?.jetton_content?.data ?: return null - return Asset( - id = AssetId(chain, tokenId), - name = data.name ?: return null, - symbol = data.symbol ?: return null, - decimals = data.decimals?.toIntOrNull() ?: return null, - type = AssetType.JETTON, - ) - } - - override suspend fun isTokenQuery(query: String): Boolean = isTokenAddress(query) - - override fun supported(chain: Chain): Boolean = this.chain == chain - - companion object { - fun isTokenAddress(tokenId: String): Boolean { - return tokenId.startsWith("EQ") && tokenId.length in 40..60 - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonNodeStatusClient.kt deleted file mode 100644 index 61d2b3d06..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonNodeStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class TonNodeStatusClient( - private val chain: Chain, - private val rpcClient: TonRpcClient, -) : NodeStatusClient { - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val resp = rpcClient.masterChainInfo("$url/api/v2/getMasterchainInfo") - NodeStatus( - url = url, - blockNumber = resp.body()?.result?.last?.seqno?.toString() ?: return@withContext null, - inSync = true, - chainId = "", - latency = resp.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonRpcClient.kt deleted file mode 100644 index b7164c9fa..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonRpcClient.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonDeserializer -import com.google.gson.JsonElement -import com.wallet.core.blockchain.ton.TonBroadcastTransaction -import com.wallet.core.blockchain.ton.TonJettonBalance -import com.wallet.core.blockchain.ton.TonJettonToken -import com.wallet.core.blockchain.ton.TonMasterchainInfo -import com.wallet.core.blockchain.ton.TonMessageTransactions -import com.wallet.core.blockchain.ton.TonResult -import com.wallet.core.blockchain.ton.TonWalletInfo -import kotlinx.serialization.SerialName -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query -import retrofit2.http.Url -import java.lang.reflect.Type - -interface TonRpcClient { - - @GET("/api/v2/getAddressBalance") - suspend fun balance(@Query("address") address: String): Result> - - @GET("/api/v2/getWalletInformation") - suspend fun walletInfo(@Query("address") address: String): Result> - - @POST("/api/v2/sendBocReturnHash") - suspend fun broadcast(@Body boc: Boc): Result> - - @GET("/api/v3/transactionsByMessage") - suspend fun transaction(@Query("msg_hash") hash: String): Result - - @GET("/api/v2/getTokenData") - suspend fun tokenData(@Query("address") address: String): Result> - - @GET("/api/v3/jetton/wallets?limit=100&offset=0") - suspend fun getJettonWallets(@Query("owner_address") ownerAddress: String): JettonWalletsResponse - - @GET("/api/v2/getTokenData") - suspend fun tokenBalance(@Query("address") address: String): Result> - - @GET("/api/v2/getAddressState") - suspend fun addressState(@Query("address") address: String): Result> - - @GET//("/api/v2/getMasterchainInfo") - suspend fun masterChainInfo(@Url string: String): Response> - - data class Boc( - val boc: String - ) - - data class JetonAddress( - val b64: String, - val len: Long, - ) - - data class JettonWalletsResponse( - val jetton_wallets: List - ) - - data class JettonWallet( - val address: String, - @SerialName("deserialize_biguint_from_str") val balance: String, - val jetton: String, - ) - - class JetonAddressSerializer : JsonDeserializer { - - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext? - ): JetonAddress? { - val jObj = json?.asJsonObject ?: return null - val data = jObj - .getAsJsonObject("result") - .getAsJsonArray("stack") - .get(0).asJsonArray[1]?.asJsonObject - ?.getAsJsonObject("object") - ?.getAsJsonObject("data") ?: return null - return JetonAddress( - b64 = data.get("b64")?.asString ?: return null, - len = data.get("len")?.asLong ?: return null, - ) - } - - } - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignClient.kt index 14f2e69bd..43e925c98 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignClient.kt @@ -3,9 +3,10 @@ package com.gemwallet.android.blockchain.clients.ton import com.gemwallet.android.blockchain.clients.SignClient import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority +import uniffi.gemstone.GemFeeOption import wallet.core.java.AnySigner import wallet.core.jni.CoinType import wallet.core.jni.proto.TheOpenNetwork @@ -23,10 +24,10 @@ class TonSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = (chainData as TonSignerPreloader.TonChainData) + val chainData = (chainData as TonChainData) val message = TheOpenNetwork.Transfer.newBuilder().apply { this.dest = params.destination().address this.amount = ByteString.copyFrom(finalAmount.toByteArray()) @@ -39,7 +40,7 @@ class TonSignClient( this.bounceable = false }.build() return sign( - sequence = chainData.sequence, + sequence = chainData.sequence.toInt(), expireAt = chainData.expireAt, message = message, privateKey = privateKey @@ -50,10 +51,10 @@ class TonSignClient( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val meta = chainData as TonSignerPreloader.TonChainData + val meta = chainData as TonChainData val jettonTransfer = TheOpenNetwork.JettonTransfer.newBuilder().apply { this.jettonAmount = ByteString.copyFrom(finalAmount.toByteArray()) @@ -64,7 +65,7 @@ class TonSignClient( val message = TheOpenNetwork.Transfer.newBuilder().apply { this.dest = meta.jettonAddress - this.amount = ByteString.copyFrom((meta.fee().options[tokenAccountCreationKey] ?: BigInteger.ZERO).toByteArray()) + this.amount = ByteString.copyFrom((fee.options[GemFeeOption.TOKEN_ACCOUNT_CREATION.name] ?: BigInteger.ZERO).toByteArray()) if (!params.memo().isNullOrEmpty()) { this.comment = params.memo() } @@ -73,7 +74,7 @@ class TonSignClient( this.bounceable = true }.build() return sign( - sequence = chainData.sequence, + sequence = chainData.sequence.toInt(), expireAt = chainData.expireAt, message = message, privateKey = privateKey @@ -84,11 +85,11 @@ class TonSignClient( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val data = params.swapData - val chainData = (chainData as TonSignerPreloader.TonChainData) + val chainData = (chainData as TonChainData) val message = TheOpenNetwork.Transfer.newBuilder().apply { this.dest = params.destination().address this.amount = ByteString.copyFrom(params.fromAmount.toByteArray()) @@ -98,7 +99,7 @@ class TonSignClient( this.customPayload = data }.build() return sign( - sequence = chainData.sequence, + sequence = chainData.sequence.toInt(), expireAt = chainData.expireAt, message = message, privateKey = privateKey diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignerPreloader.kt deleted file mode 100644 index e0d32e1c5..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonSignerPreloader.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -internal const val tokenAccountCreationKey: String = "tokenAccountCreation" - -class TonSignerPreloader( - private val chain: Chain, - private val rpcClient: TonRpcClient, -) : NativeTransferPreloader, TokenTransferPreloader, SwapTransactionPreloader { - - private val feeCalculator = TonFeeCalculator(chain, rpcClient) - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - val fee = feeCalculator.calculateNative() - val seqno = rpcClient.walletInfo(params.from.address).getOrNull()?.result?.seqno ?: 0 - return SignerParams( - input = params, - chainData = TonChainData(seqno, fee) - ) - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams = withContext(Dispatchers.IO) { - val hexTokenId = uniffi.gemstone.tonBase64ToHexAddress(params.assetId.tokenId ?: throw IllegalArgumentException("No token id")) - val getJettonAddress = async { rpcClient.getJettonWallets(params.from.address) } - - - //uniffi.gemstone.tonBase64ToHexAddress(params.assetId.tokenId!!) -// async { jettonAddress(rpcClient, params.assetId.tokenId!!, params.from.address) } - val getWalletInfo = async { rpcClient.walletInfo(params.from.address).getOrNull() } - val getFee = async { feeCalculator.calculateToken(params.assetId, params.destination().address, params.memo()) } - - val seqno = getWalletInfo.await()?.result?.seqno ?: 0 - val jettonWallets = getJettonAddress.await() - val jettonAddress = jettonWallets.jetton_wallets.firstOrNull { it.jetton.lowercase() == hexTokenId }?.address - ?: throw IllegalArgumentException("Not load jetton wallet") - - val fee = getFee.await() - - SignerParams( - input = params, - chainData = TonChainData(seqno, fee, jettonAddress) - ) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - val fee = feeCalculator.calculateSwap() - val seqno = rpcClient.walletInfo(params.from.address).getOrNull()?.result?.seqno ?: 0 - return SignerParams( - input = params, - chainData = TonChainData(seqno, fee) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class TonChainData( - val sequence: Int, - val fee: Fee, - val jettonAddress: String? = null, - val expireAt: Int? = null - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonTransactionStatusClient.kt deleted file mode 100644 index a0a086330..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/ton/TonTransactionStatusClient.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.gemwallet.android.blockchain.clients.ton - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionNotFound -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class TonTransactionStatusClient( - private val chain: Chain, - private val rpcClient: TonRpcClient, -) : TransactionStatusClient { - - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val resp = rpcClient.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - - val transaction = resp.transactions.firstOrNull() ?: throw TransactionNotFound() - val transactionState = when { - transaction.out_msgs.firstOrNull()?.let { it.bounce && it.bounced } != false -> TransactionState.Failed - else -> TransactionState.Confirmed - } - return TransactionChanges(state = transactionState) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronAddressStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronAddressStatusClient.kt index a35f96d42..cac0df6df 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronAddressStatusClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronAddressStatusClient.kt @@ -1,18 +1,16 @@ package com.gemwallet.android.blockchain.clients.tron import com.gemwallet.android.blockchain.clients.AddressStatusClient -import com.gemwallet.android.blockchain.clients.tron.services.TronAccountsService -import com.gemwallet.android.blockchain.clients.tron.services.getAccount import com.gemwallet.android.model.AddressStatus import com.wallet.core.primitives.Chain class TronAddressStatusClient( private val chain: Chain, - private val tronAccountsService: TronAccountsService, + private val client: TronRpcClient, ) : AddressStatusClient { override suspend fun getAddressStatus(chain: Chain, address: String): List { - val activePermission = tronAccountsService.getAccount(address, true) + val activePermission = client.getAccount(address, true) ?.active_permission ?: emptyList() return if (activePermission.filter { it.threshold > 1 }.isNotEmpty()) { listOf(AddressStatus.MultiSignature) diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronBalanceClient.kt deleted file mode 100644 index de3521120..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronBalanceClient.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.tron.services.TronAccountsService -import com.gemwallet.android.blockchain.clients.tron.services.TronCallService -import com.gemwallet.android.blockchain.clients.tron.services.TronStakeService -import com.gemwallet.android.blockchain.clients.tron.services.getAccount -import com.gemwallet.android.blockchain.clients.tron.services.staked -import com.gemwallet.android.blockchain.clients.tron.services.triggerSmartContract -import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import wallet.core.jni.Base58 -import java.math.BigInteger - -class TronBalanceClient( - private val chain: Chain, - private val accountsService: TronAccountsService, - private val tronCallService: TronCallService, - private val stakeService: TronStakeService, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? = withContext(Dispatchers.IO) { - val getAaccount = async { accountsService.getAccount(address, true) } - val getRewards = async { stakeService.getReward(address).getOrNull()?.reward?.toString() ?: "0" } - val account = getAaccount.await() ?: return@withContext null - val available = account.balance?.toString() ?: "0" - val pending = account.unfrozenV2?.mapNotNull { unfroze -> - unfroze.unfreeze_amount ?: return@mapNotNull null - }?.fold(0L) { acc, amount -> acc + amount }?.toString() ?: "0" - val rewards = getRewards.await() - val staked = account.staked(chain).toString() - - if (available == "0" && staked == "0" && rewards == "0" && pending == "0") { - return@withContext null - } - - AssetBalance.create( - chain.asset(), - available = available.toString(), - staked = staked, - pending = pending, - rewards = rewards - ) - } - - override suspend fun getTokenBalances(chain: Chain, address: String, tokens: List): List { - return tokens.mapNotNull { token -> - val tokenId = token.id.tokenId ?: return@mapNotNull null - val owner = Base58.decode(address).toHexString("") - tronCallService.triggerSmartContract( - contractAddress = Base58.decode(tokenId).toHexString(""), - functionSelector = "balanceOf(address)", - parameter = owner.padStart(64, '0'), - feeLimit = 1_000_000L, - callValue = 0L, - ownerAddress = owner, - visible = false, - ).fold( - { - val amount = BigInteger(it.constant_result?.firstOrNull() ?: "0", 16) - AssetBalance.create(token, amount.toString()) - } - ) { - null - } - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronBroadcastClient.kt deleted file mode 100644 index 2a968c754..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronBroadcastClient.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.clients.tron.services.TronBroadcastService -import com.gemwallet.android.blockchain.rpc.RpcError -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.math.decodeHex -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import okhttp3.RequestBody.Companion.toRequestBody - -class TronBroadcastClient( - private val chain: Chain, - private val rpcClient: TronBroadcastService, -) : BroadcastClient { - - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val requestData = signedMessage.toRequestBody(Mime.Json.value) - val data = rpcClient.broadcast(requestData).getOrNull() ?: throw ServiceError.NetworkError - if (data.result == true) { - return data.txid - } else { - throw RpcError.BroadcastFail(String(data.message.decodeHex())) - } - throw RpcError.TransactionSendError - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronChainData.kt new file mode 100644 index 000000000..ff6b7f975 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronChainData.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.blockchain.clients.tron + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class TronChainData( + val blockNumber: ULong, + val blockVersion: ULong, + val txTrieRoot: String, + val witnessAddress: String, + val parentHash: String, + val blockTimestamp: ULong, + val votes: Map = emptyMap() +) : ChainSignData + +fun GemTransactionLoadMetadata.Tron.toChainData(): TronChainData { + return TronChainData( + blockNumber = blockNumber, + blockVersion = blockVersion, + blockTimestamp = blockTimestamp, + txTrieRoot = transactionTreeRoot, + witnessAddress = witnessAddress, + parentHash = parentHash, + votes = votes + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronFeeCalculator.kt deleted file mode 100644 index b5ba70307..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronFeeCalculator.kt +++ /dev/null @@ -1,130 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.tron.services.TronCallService -import com.gemwallet.android.blockchain.clients.tron.services.TronNodeStatusService -import com.gemwallet.android.blockchain.clients.tron.services.staked -import com.gemwallet.android.blockchain.clients.tron.services.triggerSmartContract -import com.gemwallet.android.math.toHexString -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.blockchain.tron.TronAccountUsage -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import wallet.core.jni.Base58 -import java.math.BigDecimal -import java.math.BigInteger - -class TronFeeCalculator( - private val chain: Chain, - private val nodeStatusService: TronNodeStatusService, - private val callService: TronCallService, -) { - val baseFee = BigInteger.valueOf(280_000) - - suspend fun calculate(inParams: ConfirmParams.Stake, account: TronAccount?, accountUsage: TronAccountUsage?) = withContext(Dispatchers.IO) { - if (accountUsage == null || account == null) { - throw Exception("Account doesn't available (empty balance?)") - } - - val availableBandwidth = (accountUsage.freeNetLimit ?: 0) - (accountUsage.freeNetUsed ?: 0) - val fee = when (inParams) { - is ConfirmParams.Stake.DelegateParams -> if (availableBandwidth >= 580) BigInteger.ZERO else baseFee - is ConfirmParams.Stake.UndelegateParams -> if (account.staked(chain) > inParams.amount) { - if (availableBandwidth >= 580) BigInteger.ZERO else baseFee * BigInteger.valueOf(2) - } else { - if (availableBandwidth >= 300) BigInteger.ZERO else baseFee - } - is ConfirmParams.Stake.RedelegateParams, - is ConfirmParams.Stake.RewardsParams, - is ConfirmParams.Stake.WithdrawParams -> if (availableBandwidth >= 300) BigInteger.ZERO else baseFee - } - Fee(FeePriority.Normal, AssetId(chain), fee) - } - - suspend fun calculate(inParams: ConfirmParams.TransferParams.Native, account: TronAccount?, accountUsage: TronAccountUsage?) = withContext(Dispatchers.IO) { - val getParams = async { nodeStatusService.getChainParameters().fold({ it.chainParameter }) { null } } - val params = getParams.await() - - val isNewAccount = account?.address.isNullOrEmpty() - - val newAccountFee = params?.firstOrNull{ it.key == "getCreateAccountFee" }?.value - val newAccountFeeInSmartContract = params?.firstOrNull { it.key == "getCreateNewAccountFeeInSystemContract" }?.value - val availableBandwidth = (accountUsage?.freeNetLimit ?: 0) - (accountUsage?.freeNetUsed ?: 0) - val coinTransferFee = if (availableBandwidth >= 300) BigInteger.ZERO else baseFee - - if (newAccountFeeInSmartContract == null || newAccountFee == null) { - throw Exception("Tron unknown key") - } - - val fee = if (isNewAccount) { - coinTransferFee + BigInteger.valueOf(newAccountFee + newAccountFeeInSmartContract) - } else { - coinTransferFee - } - Fee(FeePriority.Normal, AssetId(chain), fee) - } - - suspend fun calculate(inParams: ConfirmParams.TransferParams.Token, account: TronAccount?, accountUsage: TronAccountUsage?) = withContext(Dispatchers.IO) { - val getParams = async { nodeStatusService.getChainParameters().fold({ it.chainParameter }) { null } } - - // https://developers.tron.network/docs/set-feelimit#how-to-estimate-energy-consumption - val gasLimit = estimateTRC20Transfer( - ownerAddress = inParams.from.address, - recipientAddress = inParams.destination.address, - contractAddress = inParams.assetId.tokenId ?: throw IllegalArgumentException("Incorrect contract on fee calculation"), - value = inParams.amount, - ) - - val isNewAccount = account?.address.isNullOrEmpty() - val params = getParams.await() - val newAccountFeeInSmartContract = params?.firstOrNull { it.key == "getCreateNewAccountFeeInSystemContract" }?.value - val energyFee = params?.firstOrNull { it.key == "getEnergyFee" }?.value - val availableEnergy = BigInteger.valueOf(accountUsage?.EnergyLimit ?: 0L) - BigInteger.valueOf(accountUsage?.EnergyUsed ?: 0L) - val energyShortfall = BigInteger.ZERO.max(gasLimit.let { it.add(it.multiply(BigDecimal(0.2))).toBigInteger() } - availableEnergy) - - if (newAccountFeeInSmartContract == null || energyFee == null) { - throw Exception("Tron unknown key") - } - - val tokenTransferFee = BigInteger.valueOf(energyFee) * energyShortfall - val fee = if (isNewAccount) { - tokenTransferFee + BigInteger.valueOf(newAccountFeeInSmartContract) - } else { - tokenTransferFee - } - Fee(FeePriority.Normal, AssetId(chain), fee) - } - - // https://developers.tron.network/docs/set-feelimit#how-to-estimate-energy-consumption - private suspend fun estimateTRC20Transfer( - ownerAddress: String, - recipientAddress: String, - contractAddress: String, - value: BigInteger - ): BigDecimal { - val address = Base58.decode(recipientAddress).toHexString("") - val parameter = arrayOf( - address, - value.toByteArray().toHexString("") - ).joinToString(separator = "") { it.padStart(64, '0') } - val response = callService.triggerSmartContract( - contractAddress = contractAddress, - functionSelector = "transfer(address,uint256)", - parameter = parameter, - feeLimit = 0L, - callValue = 0L, - ownerAddress = ownerAddress, - visible = true - ) - val result = response.getOrNull() - if (result == null || !result.result.message.isNullOrEmpty()) { - throw IllegalStateException("Can't get gas limit") - } - return BigDecimal.valueOf(result.energy_used.toLong()) - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronGetTokenClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronGetTokenClient.kt deleted file mode 100644 index 2033bce4d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronGetTokenClient.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.GetTokenClient -import com.gemwallet.android.blockchain.clients.tron.services.triggerSmartContract -import com.gemwallet.android.blockchain.operators.walletcore.WCChainTypeProxy -import com.gemwallet.android.math.decodeHex -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.AssetType -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import wallet.core.jni.AnyAddress -import wallet.core.jni.Base58 -import wallet.core.jni.EthereumAbiValue -import java.math.BigInteger - -class TronGetTokenClient( - private val chain: Chain, - private val rpcClient: TronRpcClient, -) : GetTokenClient { - override suspend fun getTokenData(tokenId: String): Asset? = withContext(Dispatchers.IO) { - val coinType = WCChainTypeProxy().invoke(chain) - if (!AnyAddress.isValid(tokenId, coinType)) { - return@withContext null - } - val contract = AnyAddress(tokenId, coinType).description() - val getName = async { getName(contract) } - val getSymbol = async { getSymbol(contract) } - val getDecimals = async { getDecimals(contract) } - val name = getName.await() ?: return@withContext null - val symbol = getSymbol.await() ?: return@withContext null - val decimals = getDecimals.await() ?: return@withContext null - - Asset( - id = AssetId(chain, tokenId), - name = name, - symbol = symbol, - decimals = decimals, - type = AssetType.TRC20, - ) - } - - override suspend fun isTokenQuery(query: String): Boolean = isTokenAddress(query) - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private suspend fun getName(contract: String): String? { - return getTokenString(contract, "name()") - } - - private suspend fun getSymbol(contract: String): String? { - return getTokenString(contract, "symbol()") - } - - private suspend fun getDecimals(contract: String): Int? { - val result = smartContractCallFunction(contract, "decimals()") ?: return null - val decimal = BigInteger(result, 16) - return decimal.toInt() - } - - private suspend fun getTokenString(contract: String, function: String): String? { - val result = smartContractCallFunction(contract, function) ?: return null - return decodeAbi(result) - } - - private suspend fun smartContractCallFunction(contract: String, function: String): String? { - val contract = "41" + Base58.decode(contract).toHexString("").drop(2) - val result = rpcClient.triggerSmartContract( - contractAddress = contract, - functionSelector = function, - parameter = null, - feeLimit = null, - callValue = null, - ownerAddress = contract, - visible = null, - ).getOrNull() - return result?.constant_result?.firstOrNull() - } - - private fun decodeAbi(hexString: String): String? { - val data = hexString.decodeHex() - if (data.size < 32) { - return null - } - return EthereumAbiValue.decodeValue(data.drop(32).toByteArray(), "string") - } - - companion object { - fun isTokenAddress(tokenId: String): Boolean { - return tokenId.startsWith("T") && tokenId.length in 30..50 - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronNodeStatusClient.kt deleted file mode 100644 index 2fe520197..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronNodeStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class TronNodeStatusClient( - private val chain: Chain, - private val rpcClient: TronRpcClient, -) : NodeStatusClient { - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val resp = rpcClient.nowBlock("$url/wallet/getnowblock") - NodeStatus( - url = url, - blockNumber = resp.body()?.block_header?.raw_data?.number?.toString() ?: return@withContext null, - inSync = true, - chainId = "", - latency = resp.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronRpcClient.kt index c1e295da2..8035d9c2d 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronRpcClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronRpcClient.kt @@ -1,24 +1,85 @@ package com.gemwallet.android.blockchain.clients.tron -import com.gemwallet.android.blockchain.clients.tron.services.TronAccountsService -import com.gemwallet.android.blockchain.clients.tron.services.TronBroadcastService -import com.gemwallet.android.blockchain.clients.tron.services.TronCallService -import com.gemwallet.android.blockchain.clients.tron.services.TronNodeStatusService -import com.gemwallet.android.blockchain.clients.tron.services.TronStakeService -import com.wallet.core.blockchain.tron.TronTransactionReceipt +import android.util.Log +import com.gemwallet.android.ext.asset +import com.gemwallet.android.math.toHexString +import com.wallet.core.blockchain.tron.TronAccount +import com.wallet.core.blockchain.tron.TronAccountRequest +import com.wallet.core.blockchain.tron.TronAccountUsage +import com.wallet.core.blockchain.tron.TronBlock +import com.wallet.core.blockchain.tron.TronChainParameters +import com.wallet.core.blockchain.tron.TronSmartContractResult +import com.wallet.core.primitives.Chain import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.POST +import wallet.core.jni.Base58 +import java.math.BigInteger -interface TronRpcClient : - TronAccountsService, - TronCallService, - TronStakeService, - TronNodeStatusService, - TronBroadcastService -{ +interface TronRpcClient { + @GET("/wallet/getchainparameters") + suspend fun getChainParameters(): Result - @POST("/wallet/gettransactioninfobyid") - suspend fun transaction(@Body value: TronValue): Result + @POST("/wallet/getnowblock") + suspend fun nowBlock(): Result - class TronValue(val value: String) + @POST("/wallet/triggerconstantcontract") + suspend fun triggerSmartContract(@Body addressRequest: Any): Result + + @POST("/wallet/getaccount") + suspend fun getAccount(@Body addressRequest: TronAccountRequest): Result + + @POST("/wallet/getaccountnet") + suspend fun getAccountUsage(@Body addressRequest: TronAccountRequest): Result +} + +fun TronAccount.staked(chain: Chain): BigInteger { + val votes = votes ?: emptyList() + val totalVotes = votes.fold(0L) { acc, item -> acc + item.vote_count } + return BigInteger.valueOf(totalVotes) * BigInteger.TEN.pow(chain.asset().decimals) +} + +suspend fun TronRpcClient.triggerSmartContract( + contractAddress: String, + functionSelector: String, + parameter: String? = null, + feeLimit: Long? = null, + callValue: Long? = null, + ownerAddress: String, + visible: Boolean? = null, +): Result { + val call = mapOf( + "contract_address" to contractAddress, + "function_selector" to functionSelector, + "parameter" to parameter, + "fee_limit" to feeLimit, + "call_value" to callValue, + "owner_address" to ownerAddress, + "visible" to visible, + ) + return triggerSmartContract(call) +} + +suspend fun TronRpcClient.getAccount(address: String, visible: Boolean = false): TronAccount? { + return try { + val result = getAccount( + TronAccountRequest( + address = address, + visible = visible + ) + ) + result.getOrThrow() + } catch (err: Throwable) { + Log.d("TRON-ACCOUNT", "Error: ", err) + null + } +} + +suspend fun TronRpcClient.getAccountUsage(address: String): TronAccountUsage? { + return getAccountUsage( + TronAccountRequest( + address = Base58.decode(address).toHexString(""), + visible = false + ) + ).getOrNull() } \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignClient.kt index 589f0758b..e96747708 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignClient.kt @@ -7,9 +7,9 @@ import com.gemwallet.android.math.decodeHex import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import wallet.core.java.AnySigner import wallet.core.jni.AnyAddress import wallet.core.jni.Base58 @@ -29,46 +29,47 @@ class TronSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val contract = TransferContract.newBuilder().apply { this.amount = finalAmount.toLong() this.ownerAddress = params.from.address this.toAddress = params.destination().address }.build() - return signTransfer(chainData, contract, privateKey) + return signTransfer(chainData, contract, fee, privateKey) } override suspend fun signTokenTransfer( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val contract = TransferTRC20Contract.newBuilder().apply { this.contractAddress = params.assetId.tokenId!! this.ownerAddress = params.from.address this.toAddress = params.destination().address this.amount = ByteString.copyFrom(finalAmount.toByteArray()) }.build() - return signTransfer(chainData, contract, privateKey) + return signTransfer(chainData, contract, fee, privateKey) } private fun signTransfer( - chainData: TronSignerPreloader.TronChainData, + chainData: TronChainData, contract: Any, + fee: Fee, privateKey: ByteArray, ): List { val transaction = Tron.Transaction.newBuilder().apply { this.blockHeader = Tron.BlockHeader.newBuilder().apply { - this.number = chainData.number + this.number = chainData.blockNumber.toLong() this.parentHash = ByteString.copyFrom(chainData.parentHash.decodeHex()) - this.timestamp = chainData.timestamp - this.version = chainData.version.toInt() + this.timestamp = chainData.blockTimestamp.toLong() + this.version = chainData.blockVersion.toInt() this.witnessAddress = ByteString.copyFrom(chainData.witnessAddress.decodeHex()) this.txTrieRoot = ByteString.copyFrom(chainData.txTrieRoot.decodeHex()) }.build() @@ -76,9 +77,9 @@ class TronSignClient( is TransferTRC20Contract -> this.transferTrc20Contract = contract is TransferContract -> this.transfer = contract } - this.expiration = chainData.timestamp + 10 * DateUtils.HOUR_IN_MILLIS - this.timestamp = chainData.timestamp - this.feeLimit = chainData.fee().amount.toLong() + this.expiration = chainData.blockTimestamp.toLong() + 10 * DateUtils.HOUR_IN_MILLIS + this.timestamp = chainData.blockTimestamp.toLong() + this.feeLimit = fee.amount.toLong() } val signInput = Tron.SigningInput.newBuilder().apply { this.transaction = transaction.build() @@ -92,10 +93,10 @@ class TronSignClient( params: ConfirmParams.Stake.DelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val freezContract = Tron.FreezeBalanceV2Contract.newBuilder().apply { this.ownerAddress = params.from.address this.frozenBalance = params.amount.toLong() @@ -103,8 +104,8 @@ class TronSignClient( }.build() val voteContract = createVoteContract(chainData, params.from.address) return listOf( - sign(chainData, freezContract, privateKey), - sign(chainData, voteContract, privateKey), + sign(chainData, freezContract, fee, privateKey), + sign(chainData, voteContract, fee, privateKey), ) } @@ -112,10 +113,10 @@ class TronSignClient( params: ConfirmParams.Stake.UndelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val votes = chainData.votes return listOfNotNull( Tron.UnfreezeBalanceV2Contract.newBuilder().apply { @@ -126,7 +127,7 @@ class TronSignClient( if (votes.isEmpty()) null else createVoteContract(chainData, params.from.address), ) .map { - sign(chainData, it, privateKey) + sign(chainData, it, fee, privateKey) } } @@ -134,27 +135,27 @@ class TronSignClient( params: ConfirmParams.Stake.RedelegateParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val voteContract = createVoteContract(chainData, params.from.address) - return listOf(sign(chainData, voteContract, privateKey)) + return listOf(sign(chainData, voteContract, fee, privateKey)) } override suspend fun signRewards( params: ConfirmParams.Stake.RewardsParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val contract = Tron.WithdrawBalanceContract.newBuilder().apply { this.ownerAddress = params.from.address }.build() return listOf( - sign(chainData, contract, privateKey) + sign(chainData, contract, fee, privateKey) ) } @@ -162,15 +163,15 @@ class TronSignClient( params: ConfirmParams.Stake.WithdrawParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val contract = Tron.WithdrawExpireUnfreezeContract.newBuilder().apply { this.ownerAddress = params.from.address }.build() return listOf( - sign(chainData, contract, privateKey) + sign(chainData, contract, fee, privateKey) ) } @@ -178,7 +179,7 @@ class TronSignClient( params: ConfirmParams.TokenApprovalParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val spender = Base58.decodeNoCheck(params.data).drop(0).toByteArray() @@ -188,17 +189,17 @@ class TronSignClient( contractAddress = params.contract data = ByteString.copyFrom(callData) } - return listOf(sign(chainData as TronSignerPreloader.TronChainData, approvalContract, privateKey)) + return listOf(sign(chainData as TronChainData, approvalContract, fee, privateKey)) } override suspend fun signSwap( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { - val chainData = chainData as TronSignerPreloader.TronChainData + val chainData = chainData as TronChainData val data = params.swapData val callValue = params.value.toLong() val contract = Tron.TriggerSmartContract.newBuilder().apply { @@ -218,27 +219,27 @@ class TronSignClient( ), chainData = chainData, finalAmount = BigInteger.ZERO, - feePriority = feePriority, + fee = fee, privateKey = privateKey ) } ?: emptyList() - return listOf(sign(chainData, contract, privateKey)) + approval + return listOf(sign(chainData, contract, fee, privateKey)) + approval } - private fun createVoteContract(chainData: TronSignerPreloader.TronChainData, owner: String) = Tron.VoteWitnessContract.newBuilder().apply { + private fun createVoteContract(chainData: TronChainData, owner: String) = Tron.VoteWitnessContract.newBuilder().apply { this.ownerAddress = owner this.support = true this.addAllVotes( chainData.votes.map { Tron.VoteWitnessContract.Vote.newBuilder().apply { this.voteAddress = it.key - this.voteCount = it.value + this.voteCount = it.value.toLong() }.build() } ) }.build() - private fun sign(chainData: TronSignerPreloader.TronChainData, contract: Any, privateKey: ByteArray): ByteArray { + private fun sign(chainData: TronChainData, contract: Any, fee: Fee, privateKey: ByteArray): ByteArray { val transaction = Tron.Transaction.newBuilder().apply { when (contract) { is TransferContract -> this.transfer = contract @@ -251,17 +252,17 @@ class TronSignClient( is Tron.TriggerSmartContract -> this.triggerSmartContract = contract } this.blockHeader = Tron.BlockHeader.newBuilder().apply { - this.number = chainData.number + this.number = chainData.blockNumber.toLong() this.parentHash = ByteString.copyFrom(chainData.parentHash.decodeHex()) - this.timestamp = chainData.timestamp - this.version = chainData.version.toInt() + this.timestamp = chainData.blockTimestamp.toLong() + this.version = chainData.blockVersion.toInt() this.witnessAddress = ByteString.copyFrom(chainData.witnessAddress.decodeHex()) this.txTrieRoot = ByteString.copyFrom(chainData.txTrieRoot.decodeHex()) }.build() - this.expiration = chainData.timestamp + 10 * DateUtils.HOUR_IN_MILLIS - this.timestamp = chainData.timestamp - this.feeLimit = chainData.fee().amount.toLong() + this.expiration = chainData.blockTimestamp.toLong() + 10 * DateUtils.HOUR_IN_MILLIS + this.timestamp = chainData.blockTimestamp.toLong() + this.feeLimit = fee.amount.toLong() } val signInput = Tron.SigningInput.newBuilder().apply { this.transaction = transaction.build() diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignerPreloader.kt deleted file mode 100644 index 91f3b727d..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronSignerPreloader.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.StakeTransactionPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.tron.services.TronAccountsService -import com.gemwallet.android.blockchain.clients.tron.services.TronCallService -import com.gemwallet.android.blockchain.clients.tron.services.TronNodeStatusService -import com.gemwallet.android.blockchain.clients.tron.services.getAccount -import com.gemwallet.android.blockchain.clients.tron.services.getAccountUsage -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.blockchain.tron.TronAccountUsage -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import java.math.BigInteger - -class TronSignerPreloader( - private val chain: Chain, - private val nodeStatusService: TronNodeStatusService, - private val accountsService: TronAccountsService, - callService: TronCallService, -) : NativeTransferPreloader, TokenTransferPreloader, StakeTransactionPreloader, SwapTransactionPreloader { - val feeCalculator = TronFeeCalculator(chain, nodeStatusService, callService) - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - return preload( - params, { account, usage -> - feeCalculator.calculate(params, account, usage) - } - ) { emptyMap() } - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams { - return preload( - params, { account, usage -> - feeCalculator.calculate(params, account, usage) - } - ) { emptyMap() } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - override suspend fun preloadStake(params: ConfirmParams.Stake): SignerParams = withContext(Dispatchers.IO) { - preload( - params = params, - feeCalc = { account, usage -> - feeCalculator.calculate(params, account, usage) - } - ) { account -> - val newVote = (params.amount / BigInteger.TEN.pow(chain.asset().decimals)).toLong() - val votes = (account?.votes ?: emptyList()).groupBy { it.vote_address }.mapValues { - it.value.fold(0L) { acc, v -> acc + v.vote_count} - }.toMutableMap() - when (params) { - is ConfirmParams.Stake.DelegateParams -> votes[params.validatorId] = (votes[params.validatorId] ?: 0L) + newVote - is ConfirmParams.Stake.UndelegateParams -> votes[params.validatorId] = (votes[params.validatorId] ?: 0L) - newVote - is ConfirmParams.Stake.RedelegateParams -> { - votes[params.srcValidatorId] = (votes[params.srcValidatorId] ?: 0L) - newVote - votes[params.dstValidatorId] = (votes[params.dstValidatorId] ?: 0L) + newVote - } - is ConfirmParams.Stake.RewardsParams, - is ConfirmParams.Stake.WithdrawParams -> {} - } - votes.filter { it.value > 0 } - } - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - TODO("Not yet implemented") - } - - private suspend fun preload( - params: ConfirmParams, - feeCalc: suspend (TronAccount?, TronAccountUsage?) -> Fee, - votes: suspend (TronAccount?) -> Map, - ): SignerParams = withContext(Dispatchers.IO) { - val getAccountUsage = async { accountsService.getAccountUsage(params.from.address) } - val getAccount = async { accountsService.getAccount(params.from.address, true) } - val nowBlockJob = async { nodeStatusService.nowBlock() } - - val nowBlock = nowBlockJob.await().getOrThrow() - val account = getAccount.await() - val accountUsage = getAccountUsage.await() - - val fee = feeCalc(account, accountUsage) - - SignerParams( - input = params, - chainData = TronChainData( - number = nowBlock.block_header.raw_data.number, - version = nowBlock.block_header.raw_data.version, - txTrieRoot = nowBlock.block_header.raw_data.txTrieRoot, - witnessAddress = nowBlock.block_header.raw_data.witness_address, - parentHash = nowBlock.block_header.raw_data.parentHash, - timestamp = nowBlock.block_header.raw_data.timestamp, - fee = fee, - votes = votes(account) - ) - ) - } - - data class TronChainData( - val number: Long, - val version: Long, - val txTrieRoot: String, - val witnessAddress: String, - val parentHash: String, - val timestamp: Long, - val fee: Fee, - val votes: Map = emptyMap() - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fee - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronStakeClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronStakeClient.kt deleted file mode 100644 index c2b792798..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronStakeClient.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.StakeClient -import com.gemwallet.android.blockchain.clients.tron.services.TronAccountsService -import com.gemwallet.android.blockchain.clients.tron.services.TronStakeService -import com.gemwallet.android.blockchain.clients.tron.services.getAccount -import com.gemwallet.android.ext.asset -import com.gemwallet.android.math.decodeHex -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationBase -import com.wallet.core.primitives.DelegationState -import com.wallet.core.primitives.DelegationValidator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext -import wallet.core.jni.Base58 -import java.math.BigInteger -import kotlin.math.roundToLong - -class TronStakeClient( - private val chain: Chain, - private val stakeService: TronStakeService, - private val accountsService: TronAccountsService, -) : StakeClient { - override suspend fun getValidators( - chain: Chain, - apr: Double - ): List { - val validators = stakeService.listwitnesses().getOrNull()?.witnesses - ?.mapNotNull { - DelegationValidator( - id = addressBase58(it.address) ?: return@mapNotNull null, - chain = chain, - name = "", - isActive = it.isJobs == true, - commision = 0.0, - apr = apr, - ) - } ?: emptyList() - return validators + getSystem() - } - - - override suspend fun getStakeDelegations( - chain: Chain, - address: String, - apr: Double - ): List = withContext(Dispatchers.IO) { - val getAccount = async { accountsService.getAccount(address, true) } - val getValidators = async { getValidators(chain, apr = 0.0) } - val getReward = async { stakeService.getReward(address).getOrNull()?.reward ?: 0L } - - val account = getAccount.await() - val validators = getValidators.await() - val reward = getReward.await() - - val pendingDelegations = (account?.unfrozenV2 ?: emptyList()).mapNotNull { unfrozen -> - val expireTime = unfrozen.unfreeze_expire_time ?: return@mapNotNull null - val amount = unfrozen.unfreeze_amount ?: return@mapNotNull null - val completionDate = expireTime - val state = if (System.currentTimeMillis() < expireTime) DelegationState.Pending else DelegationState.AwaitingWithdrawal - val balance = BigInteger.valueOf(amount) - - DelegationBase( - assetId = AssetId(chain), - state = state, - balance = balance.toString(), - shares = "", - rewards = "0", - completionDate = completionDate, - delegationId = completionDate.toString(), - validatorId = getSystem().id, - ) - } - - val votes = account?.votes ?: emptyList() - val delegations = votes.mapNotNull { vote -> - val validator = validators.firstOrNull { it.id == vote.vote_address } ?: return@mapNotNull null - val balance = BigInteger.valueOf(vote.vote_count) * BigInteger.TEN.pow(chain.asset().decimals) - val totalVotes = votes.fold(0L) { acc, item -> acc + item.vote_count } - val rewards = if (totalVotes <= 0) { - BigInteger.valueOf(reward) - } else { - val proportion = vote.vote_count.toDouble() / totalVotes.toDouble() - val rewardForVote = reward.toDouble() * proportion - val roundedRewardForVote = rewardForVote.roundToLong() - BigInteger.valueOf(roundedRewardForVote) - } - - DelegationBase( - assetId = AssetId(chain), - state = DelegationState.Active, - balance = balance.toString(), - shares = "", - rewards = rewards.toString(), - completionDate = null, - delegationId = "${balance}_${reward}".toString(), - validatorId = validator.id, - ) - } - pendingDelegations + delegations - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - private fun getSystem() = DelegationValidator( - id = "unstaking", - chain = chain, - name = "Unstaking", - isActive = true, - commision = 0.0, - apr = 0.0, - ) - - private fun addressBase58(hex: String): String? { - try { - return Base58.encode(hex.decodeHex()) - } catch (_: Throwable) { - return null - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronTransactionStatusClient.kt deleted file mode 100644 index 3343875c1..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/TronTransactionStatusClient.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import java.math.BigInteger - -class TronTransactionStatusClient( - private val chain: Chain, - private val rpcClient: TronRpcClient -) : TransactionStatusClient { - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val resp = rpcClient.transaction(TronRpcClient.TronValue(request.hash)).getOrNull() ?: throw ServiceUnavailable - return when { - resp.receipt != null && resp.receipt?.result == "OUT_OF_ENERGY" -> TransactionChanges(TransactionState.Reverted) - resp.result == "FAILED" -> TransactionChanges(TransactionState.Reverted) - resp.blockNumber > 0 -> { - val fee = resp.fee ?: 0 - return TransactionChanges(TransactionState.Confirmed, BigInteger.valueOf(fee.toLong())) - } - else -> TransactionChanges(TransactionState.Pending) - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronAccountsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronAccountsService.kt deleted file mode 100644 index 91ace2664..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronAccountsService.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron.services - -import android.util.Log -import com.gemwallet.android.math.toHexString -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.blockchain.tron.TronAccountRequest -import com.wallet.core.blockchain.tron.TronAccountUsage -import retrofit2.http.Body -import retrofit2.http.POST -import wallet.core.jni.Base58 - -interface TronAccountsService { - @POST("/wallet/getaccount") - suspend fun getAccount(@Body addressRequest: TronAccountRequest): Result - - @POST("/wallet/getaccountnet") - suspend fun getAccountUsage(@Body addressRequest: TronAccountRequest): Result -} - -suspend fun TronAccountsService.getAccount(address: String, visible: Boolean = false): TronAccount? { - return try { - val result = getAccount( - TronAccountRequest( - address = address, - visible = visible - ) - ) - result.getOrThrow() - } catch (err: Throwable) { - Log.d("TRON-ACCOUNT", "Error: ", err) - null - } -} - -suspend fun TronAccountsService.getAccountUsage(address: String): TronAccountUsage? { - return getAccountUsage( - TronAccountRequest( - address = Base58.decode(address).toHexString(""), - visible = false - ) - ).getOrNull() -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronBalanceService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronBalanceService.kt deleted file mode 100644 index 2872fef27..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronBalanceService.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron.services - -import com.gemwallet.android.ext.asset -import com.wallet.core.blockchain.tron.TronAccount -import com.wallet.core.primitives.Chain -import java.math.BigInteger - -fun TronAccount.staked(chain: Chain): BigInteger { - val votes = votes ?: emptyList() - val totalVotes = votes.fold(0L) { acc, item -> acc + item.vote_count } - return BigInteger.valueOf(totalVotes) * BigInteger.TEN.pow(chain.asset().decimals) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronBroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronBroadcastService.kt deleted file mode 100644 index d0174ac80..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronBroadcastService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron.services - -import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.POST - -interface TronBroadcastService { - @POST("/wallet/broadcasttransaction") - suspend fun broadcast(@Body body: RequestBody): Result -} - -data class TronTransactionBroadcast( - val result: Boolean, - val txid: String, - val message: String, -) \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronCallService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronCallService.kt deleted file mode 100644 index 241df8ae6..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronCallService.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron.services - -import com.wallet.core.blockchain.tron.TronSmartContractResult -import retrofit2.http.Body -import retrofit2.http.POST - -interface TronCallService { - @POST("/wallet/triggerconstantcontract") - suspend fun triggerSmartContract(@Body addressRequest: Any): Result -} - -suspend fun TronCallService.triggerSmartContract( - contractAddress: String, - functionSelector: String, - parameter: String? = null, - feeLimit: Long? = null, - callValue: Long? = null, - ownerAddress: String, - visible: Boolean? = null, -): Result { - val call = mapOf( - "contract_address" to contractAddress, - "function_selector" to functionSelector, - "parameter" to parameter, - "fee_limit" to feeLimit, - "call_value" to callValue, - "owner_address" to ownerAddress, - "visible" to visible, - ) - return triggerSmartContract(call) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronNodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronNodeStatusService.kt deleted file mode 100644 index 0b35b6fba..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronNodeStatusService.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron.services - -import com.wallet.core.blockchain.tron.TronBlock -import com.wallet.core.blockchain.tron.TronChainParameters -import retrofit2.Response -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Url - -interface TronNodeStatusService { - @GET("/wallet/getchainparameters") - suspend fun getChainParameters(): Result - - @POST("/wallet/getnowblock") - suspend fun nowBlock(): Result - - @POST//("/wallet/getnowblock") - suspend fun nowBlock(@Url url: String): Response -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronStakeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronStakeService.kt deleted file mode 100644 index 6d5e77f74..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/tron/services/TronStakeService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.gemwallet.android.blockchain.clients.tron.services - -import com.wallet.core.blockchain.tron.TronReward -import com.wallet.core.blockchain.tron.WitnessesList -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST - -interface TronStakeService { - @GET("/wallet/listwitnesses") - suspend fun listwitnesses(): Result - - @POST("/wallet/getReward") - suspend fun getReward(@Body address: String): Result - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpBalanceClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpBalanceClient.kt deleted file mode 100644 index f7b7c85e8..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpBalanceClient.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.xrp.services.XrpAccountsService -import com.gemwallet.android.blockchain.clients.xrp.services.account -import com.gemwallet.android.blockchain.clients.xrp.services.accountLines -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.getReserveBalance -import com.gemwallet.android.ext.getTokenActivationFee -import com.gemwallet.android.model.AssetBalance -import com.gemwallet.android.model.Crypto -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.Chain -import java.math.BigInteger - -class XrpBalanceClient( - private val chain: Chain, - private val accountsService: XrpAccountsService, -) : BalanceClient { - - override suspend fun getNativeBalance(chain: Chain, address: String): AssetBalance? { - val account = accountsService.account(address).getOrNull()?.result?.account_data ?: return null - val amount = account.Balance.toBigInteger() - val reserved = chain.getReserveBalance() + (account.OwnerCount.toBigInteger() * chain.getTokenActivationFee()) - return AssetBalance.create( - chain.asset(), - available = BigInteger.ZERO.max(amount - reserved).toString(), - reserved = reserved.toString() - ) - } - - override suspend fun getTokenBalances( - chain: Chain, - address: String, - tokens: List - ): List { - val lines = accountsService.accountLines(address).getOrNull()?.result?.lines ?: emptyList() - return tokens.map { token -> - val line = lines.firstOrNull { it.account == token.id.tokenId && it.currency.length == 40 } - - if (line == null) { - AssetBalance.create(token, available = "0", isActive = false) - } else { - val value = Crypto(line.balance.toBigDecimal(), token.decimals).atomicValue.toString() - AssetBalance.create(token, available = value, isActive = true) - } - } - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpBroadcastClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpBroadcastClient.kt deleted file mode 100644 index 60c05a4c1..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpBroadcastClient.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.BroadcastClient -import com.gemwallet.android.blockchain.rpc.ServiceError -import com.gemwallet.android.math.toHexString -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType - -class XrpBroadcastClient( - private val chain: Chain, - private val rpcClient: XrpRpcClient, -) : BroadcastClient { - override suspend fun send(account: Account, signedMessage: ByteArray, type: TransactionType): String { - val request = signedMessage.toHexString("") - val response = rpcClient.broadcast(request).getOrNull() - ?: throw ServiceError.NetworkError - - if (response.result.accepted != true && !response.result.engine_result_message.isNullOrEmpty()) { - throw Exception(response.result.engine_result_message) - } - if (response.result.tx_json?.hash.isNullOrEmpty()) { - throw Exception("Unable to get hash") - } - return response.result.tx_json?.hash!! - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpChainData.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpChainData.kt new file mode 100644 index 000000000..998a79eb6 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpChainData.kt @@ -0,0 +1,16 @@ +package com.gemwallet.android.blockchain.clients.xrp + +import com.gemwallet.android.model.ChainSignData +import uniffi.gemstone.GemTransactionLoadMetadata + +data class XrpChainData( + val sequence: Int, + val blockNumber: Int, +) : ChainSignData + +fun GemTransactionLoadMetadata.Xrp.toChainData(): XrpChainData { + return XrpChainData( + sequence = sequence.toInt(), + blockNumber = blockNumber.toInt(), + ) +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpFeeCalculator.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpFeeCalculator.kt deleted file mode 100644 index ab8bc1236..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpFeeCalculator.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.model.Fee -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import java.math.BigInteger - -class XrpFeeCalculator( - private val chain: Chain, - private val rpcClient: XrpRpcClient, -) { - suspend fun calculate(): List { - val drops = rpcClient.fee().getOrThrow().result.drops - val minimum = drops.minimum_fee.toBigInteger() - val median = drops.median_fee.toBigInteger() - - return FeePriority.entries.map { - val amount = when (it) { - FeePriority.Slow -> (median / BigInteger.TEN).max(minimum) - FeePriority.Normal -> median - FeePriority.Fast -> median * BigInteger.valueOf(2) - } - Fee(feeAssetId = AssetId(chain), priority = it, amount = amount) - } - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpMethod.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpMethod.kt deleted file mode 100644 index 173f62457..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpMethod.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.rpc.model.JSONRpcMethod - -enum class XrpMethod(val value: String) : JSONRpcMethod { - Account("account_info"), - Fee("fee"), - Transaction("tx"), - Broadcast("submit"), - LatestBlock("ledger_current"), - AccountLines("account_lines"), - ; - - override fun value(): String = value -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpNodeStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpNodeStatusClient.kt deleted file mode 100644 index d0099debf..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpNodeStatusClient.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.NodeStatusClient -import com.gemwallet.android.blockchain.rpc.getLatency -import com.gemwallet.android.model.NodeStatus -import com.wallet.core.primitives.Chain -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class XrpNodeStatusClient( - private val chain: Chain, - private val rpcClient: XrpRpcClient, -) : NodeStatusClient { - override suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? = withContext(Dispatchers.IO) { - val resp = rpcClient.latestBlock(url) - - NodeStatus( - url = url, - blockNumber = resp.body()?.result?.ledger_current_index?.toString() ?: return@withContext null, - inSync = true, - chainId = "", - latency = resp.getLatency(), - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpRpcClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpRpcClient.kt deleted file mode 100644 index 2f4038b56..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpRpcClient.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.xrp.services.XrpAccountsService -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.wallet.core.blockchain.xrp.XRPFee -import com.wallet.core.blockchain.xrp.XRPLatestBlock -import com.wallet.core.blockchain.xrp.XRPResult -import com.wallet.core.blockchain.xrp.XRPTransactionBroadcast -import com.wallet.core.blockchain.xrp.XRPTransactionStatus -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST -import retrofit2.http.Url - -interface XrpRpcClient : XrpAccountsService { - - @POST("/") - suspend fun fee(@Body request: JSONRpcRequest>>): Result> - - @POST("/") - suspend fun transaction(@Body request: JSONRpcRequest>>): Result> - - @POST("/") - suspend fun broadcast(@Body request: JSONRpcRequest>>): Result> - - @POST//("/") - suspend fun latestBlock(@Url url: String, @Body request: JSONRpcRequest>>): Response> -} - -internal suspend fun XrpRpcClient.fee(): Result> { - return fee(JSONRpcRequest.create(XrpMethod.Fee, listOf(mapOf()))) -} - -internal suspend fun XrpRpcClient.transaction(txId: String): Result> { - val request = JSONRpcRequest.create( - XrpMethod.Transaction, - listOf( - mapOf( - "transaction" to txId, - ) - ) - ) - return transaction(request) -} - -internal suspend fun XrpRpcClient.broadcast(data: String): Result> { - val request = JSONRpcRequest.create( - XrpMethod.Broadcast, - listOf( - mapOf( - "tx_blob" to data, - "fail_hard" to "true" - ) - ) - ) - return broadcast(request) -} - -internal suspend fun XrpRpcClient.latestBlock(url: String): Response> { - return latestBlock(url, JSONRpcRequest.create(XrpMethod.LatestBlock, emptyList())) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignClient.kt index babc3a448..b7e3d2f3c 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignClient.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignClient.kt @@ -6,9 +6,9 @@ import com.gemwallet.android.math.toHexString import com.gemwallet.android.model.ChainSignData import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.Crypto +import com.gemwallet.android.model.Fee import com.google.protobuf.ByteString import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority import com.wallet.core.primitives.SwapProvider import wallet.core.java.AnySigner import wallet.core.jni.proto.Ripple @@ -23,7 +23,7 @@ class XrpSignClient( params: ConfirmParams.TransferParams.Native, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val operation = OperationPayment.newBuilder().apply { @@ -31,14 +31,14 @@ class XrpSignClient( this.amount = finalAmount.toLong() this.destinationTag = try { params.memo()?.toLong() ?: 0 } catch (_: Throwable) { 0 } }.build() - return sign(params, chainData, feePriority, operation, privateKey) + return sign(params, chainData, fee, operation, privateKey) } override suspend fun signTokenTransfer( params: ConfirmParams.TransferParams.Token, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val operation = OperationPayment.newBuilder().apply { @@ -50,14 +50,14 @@ class XrpSignClient( }.build() this.destinationTag = try { params.memo()?.toLong() ?: 0 } catch (_: Throwable) { 0L } }.build() - return sign(params, chainData, feePriority, operation, privateKey) + return sign(params, chainData, fee, operation, privateKey) } override suspend fun signActivate( params: ConfirmParams.Activate, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { val operation = OperationTrustSet.newBuilder().apply { @@ -67,14 +67,14 @@ class XrpSignClient( this.issuer = params.assetId.tokenId!! }.build() }.build() - return sign(params, chainData, feePriority, operation, privateKey) + return sign(params, chainData, fee, operation, privateKey) } override suspend fun signSwap( params: ConfirmParams.SwapParams, chainData: ChainSignData, finalAmount: BigInteger, - feePriority: FeePriority, + fee: Fee, privateKey: ByteArray ): List { when (params.protocolId) { @@ -93,7 +93,7 @@ class XrpSignClient( ] } """ - return sign(params, chainData, feePriority, json, privateKey) + return sign(params, chainData, fee, json, privateKey) } else -> throw Exception("Provider doesn't support") } @@ -102,13 +102,13 @@ class XrpSignClient( private fun sign( params: ConfirmParams, chainData: ChainSignData, - feePriority: FeePriority, + fee: Fee, operation: Any, privateKey: ByteArray, ): List { - val metadata = chainData as XrpSignerPreloader.XrpChainData + val metadata = chainData as XrpChainData val signInput = Ripple.SigningInput.newBuilder().apply { - this.fee = metadata.fee(feePriority).amount.toLong() + this.fee = fee.amount.toLong() this.sequence = metadata.sequence this.account = params.from.address this.privateKey = ByteString.copyFrom(privateKey) @@ -120,7 +120,7 @@ class XrpSignClient( } }.build() val output = AnySigner.sign(signInput, WCChainTypeProxy().invoke(chain), Ripple.SigningOutput.parser()) - return listOf(output.encoded.toByteArray()) + return listOf(output.encoded.toByteArray().toHexString("").toByteArray()) } override fun supported(chain: Chain): Boolean = this.chain == chain diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignerPreloader.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignerPreloader.kt deleted file mode 100644 index 0b8665bad..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpSignerPreloader.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.ActivationTransactionPreloader -import com.gemwallet.android.blockchain.clients.BlockchainError -import com.gemwallet.android.blockchain.clients.NativeTransferPreloader -import com.gemwallet.android.blockchain.clients.SwapTransactionPreloader -import com.gemwallet.android.blockchain.clients.TokenTransferPreloader -import com.gemwallet.android.blockchain.clients.xrp.services.account -import com.gemwallet.android.model.ChainSignData -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.Fee -import com.gemwallet.android.model.SignerParams -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -class XrpSignerPreloader( - private val chain: Chain, - private val rpcClient: XrpRpcClient, -) : NativeTransferPreloader, TokenTransferPreloader, ActivationTransactionPreloader, SwapTransactionPreloader { - - private val feeCalculator = XrpFeeCalculator(chain, rpcClient) - - override suspend fun preloadNativeTransfer(params: ConfirmParams.TransferParams.Native): SignerParams { - return preload(params) - } - - override suspend fun preloadTokenTransfer(params: ConfirmParams.TransferParams.Token): SignerParams { - return preload(params) - } - - override suspend fun preloadActivate(params: ConfirmParams.Activate): SignerParams { - return preload(params) - } - - override suspend fun preloadSwap(params: ConfirmParams.SwapParams): SignerParams { - return preload(params) - } - - private suspend fun preload(params: ConfirmParams) = withContext(Dispatchers.IO) { - val (getSequence, getFee) = Pair ( - async { rpcClient.account(params.from.address).getOrNull()?.result }, - async { feeCalculator.calculate() } - ) - val account = getSequence.await() ?: throw BlockchainError.AccountNotActive - val fee = getFee.await() - - SignerParams( - params, - XrpChainData( - account.account_data?.Sequence ?: 0, - account.ledger_current_index, - fee, - ) - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain - - data class XrpChainData( - val sequence: Int, - val blockNumber: Int, - val fees: List, - ) : ChainSignData { - override fun fee(speed: FeePriority): Fee = fees.firstOrNull { it.priority == speed } ?: fees.first() - - override fun allFee(): List = fees - } -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpTransactionStatusClient.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpTransactionStatusClient.kt deleted file mode 100644 index 6b8d54244..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/XrpTransactionStatusClient.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp - -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient -import com.gemwallet.android.model.TransactionChanges -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState - -class XrpTransactionStatusClient( - private val chain: Chain, - private val rpcClient: XrpRpcClient, -) : TransactionStatusClient { - override suspend fun getStatus(request: TransactionStateRequest): TransactionChanges { - val resp = rpcClient.transaction(request.hash).getOrNull() ?: throw ServiceUnavailable - return TransactionChanges( - if (resp.result.status == "success") { - TransactionState.Confirmed - } else { - TransactionState.Pending - } - ) - } - - override fun supported(chain: Chain): Boolean = this.chain == chain -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/services/XrpAccountsService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/services/XrpAccountsService.kt deleted file mode 100644 index 1ccd88c62..000000000 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/xrp/services/XrpAccountsService.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.gemwallet.android.blockchain.clients.xrp.services - -import com.gemwallet.android.blockchain.clients.xrp.XrpMethod -import com.gemwallet.android.blockchain.rpc.model.JSONRpcRequest -import com.wallet.core.blockchain.xrp.XRPAccountLinesResult -import com.wallet.core.blockchain.xrp.XRPAccountResult -import com.wallet.core.blockchain.xrp.XRPResult -import retrofit2.http.Body -import retrofit2.http.POST - -interface XrpAccountsService { - @POST("/") - suspend fun account(@Body request: JSONRpcRequest>>): Result> - - @POST("/") - suspend fun accountLines(@Body request: JSONRpcRequest>>): Result> -} - -internal suspend fun XrpAccountsService.account(address: String): Result> { - val request = JSONRpcRequest.create( - XrpMethod.Account, - listOf( - mapOf( - "account" to address, - "ledger_index" to "current", - ) - ) - ) - return account(request) -} - -internal suspend fun XrpAccountsService.accountLines(address: String): Result> { - val request = JSONRpcRequest.create( - XrpMethod.AccountLines, - listOf( - mapOf( - "account" to address, - "ledger_index" to "current", - ) - ) - ) - return accountLines(request) -} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/model/TransactionStateRequest.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/model/TransactionStateRequest.kt new file mode 100644 index 000000000..14f8e34e5 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/model/TransactionStateRequest.kt @@ -0,0 +1,10 @@ +package com.gemwallet.android.blockchain.model + +import com.wallet.core.primitives.Chain + +class TransactionStateRequest( + val chain: Chain, + val hash: String, + val block: String, + val sender: String, +) \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/model/TransactionStatusError.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/model/TransactionStatusError.kt new file mode 100644 index 000000000..44e874d72 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/model/TransactionStatusError.kt @@ -0,0 +1,5 @@ +package com.gemwallet.android.blockchain.model + +sealed class TransactionStatusError(message: String? = null) : Exception(message) + +object ServiceUnavailable : TransactionStatusError() \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/operators/walletcore/WCChainTypeProxy.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/operators/walletcore/WCChainTypeProxy.kt index ce149cac8..53102e170 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/operators/walletcore/WCChainTypeProxy.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/operators/walletcore/WCChainTypeProxy.kt @@ -52,5 +52,6 @@ class WCChainTypeProxy : ChainTypeProxy { Chain.Stellar -> CoinType.STELLAR Chain.Polkadot -> CoinType.POLKADOT Chain.Cardano -> CoinType.CARDANO + Chain.HyperCore -> CoinType.ETHEREUM // TODO: HyperCore } } \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/rpc/Response.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/rpc/Response.kt index f82bfec93..486167e43 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/rpc/Response.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/rpc/Response.kt @@ -2,4 +2,4 @@ package com.gemwallet.android.blockchain.rpc import retrofit2.Response -fun Response.getLatency() = raw().receivedResponseAtMillis - raw().sentRequestAtMillis \ No newline at end of file +fun Response.getLatency(): ULong = (raw().receivedResponseAtMillis - raw().sentRequestAtMillis).toULong() \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BalancesService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BalancesService.kt new file mode 100644 index 000000000..1381121f5 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BalancesService.kt @@ -0,0 +1,72 @@ +package com.gemwallet.android.blockchain.services + +import com.gemwallet.android.ext.asset +import com.gemwallet.android.ext.toIdentifier +import com.gemwallet.android.model.AssetBalance +import com.wallet.core.primitives.Account +import com.wallet.core.primitives.Asset +import uniffi.gemstone.GatewayException +import uniffi.gemstone.GemGateway + +class BalancesService( + private val gateway: GemGateway, +) { + + suspend fun getNativeBalances(account: Account): AssetBalance? { + return try { + val result = gateway.getBalanceCoin(account.chain.string, account.address) + AssetBalance.Companion.create( + asset = account.chain.asset(), + available = result.balance.available, + reserved = result.balance.reserved, + isActive = result.isActive, + ) + } catch (_: GatewayException) { + null + } catch (_: Throwable) { + null + } + } + + suspend fun getDelegationBalances(account: Account): AssetBalance? { + return try { + val result = gateway.getBalanceStaking(account.chain.string, account.address) + ?: return null + AssetBalance.Companion.create( + asset = account.chain.asset(), + frozen = result.balance.frozen, + locked = result.balance.locked, + staked = result.balance.staked, + pending = result.balance.pending, + rewards = result.balance.rewards, + ) + } catch (_: GatewayException) { + null + } catch (_: Throwable) { + null + } + } + + suspend fun getTokensBalances(account: Account, tokens: List): List { + return try { + val ids = tokens.mapNotNull { it.id.tokenId } + val result = gateway.getBalanceTokens( + account.chain.string, + account.address, + ids + ) + val assetIndex = tokens.groupBy { it.id.toIdentifier() } + val balances = result.mapNotNull { + AssetBalance.Companion.create( + asset = assetIndex[it.assetId]?.firstOrNull() ?: return@mapNotNull null, + available = it.balance.available, + ) + } + balances + } catch (_: GatewayException) { + emptyList() + } catch (_: Throwable) { + emptyList() + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BroadcastService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BroadcastService.kt new file mode 100644 index 000000000..597710916 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BroadcastService.kt @@ -0,0 +1,30 @@ +package com.gemwallet.android.blockchain.services + +import com.wallet.core.primitives.Account +import com.wallet.core.primitives.Chain +import com.wallet.core.primitives.TransactionType +import uniffi.gemstone.GemBroadcastOptions +import uniffi.gemstone.GemGateway + +class BroadcastService( + private val gateway: GemGateway, +) { + + suspend fun send( + account: Account, + signedMessage: ByteArray, + type: TransactionType + ): String { + val hash = gateway.transactionBroadcast( + chain = account.chain.string, + data = String(signedMessage), + options = GemBroadcastOptions( + when (account.chain) { + Chain.Solana -> type == TransactionType.Swap + else -> false + } + ) + ) + return hash + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/NodeStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/NodeStatusService.kt new file mode 100644 index 000000000..987cbd06b --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/NodeStatusService.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.blockchain.services + +import com.gemwallet.android.model.NodeStatus +import com.wallet.core.primitives.Chain +import uniffi.gemstone.GemGateway + +class NodeStatusService( + private val gateway: GemGateway, +) { + + suspend fun getNodeStatus(chain: Chain, url: String): NodeStatus? { + return try { + val result = gateway.getNodeStatus(chain.string, url) + NodeStatus( + url = url, + chainId = result.chainId, + blockNumber = result.latestBlockNumber, + inSync = true, + latency = result.latencyMs, + loading = false + ) + } catch (_: Throwable) { + null + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClientProxy.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/SignClientProxy.kt similarity index 66% rename from blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClientProxy.kt rename to blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/SignClientProxy.kt index d7596db2a..814604651 100644 --- a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/clients/SignClientProxy.kt +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/SignClientProxy.kt @@ -1,5 +1,7 @@ -package com.gemwallet.android.blockchain.clients +package com.gemwallet.android.blockchain.services +import com.gemwallet.android.blockchain.clients.SignClient +import com.gemwallet.android.blockchain.clients.getClient import com.gemwallet.android.model.ConfirmParams import com.gemwallet.android.model.SignerParams import com.wallet.core.primitives.Chain @@ -35,19 +37,22 @@ class SignClientProxy( val chain = params.input.asset.id.chain val client = clients.getClient(chain) ?: throw Exception("Chain isn't support") val input = params.input + val data = params.data(feePriority) + val fee = data.fee + val chainData = data.chainData return when (input) { - is ConfirmParams.Stake.DelegateParams -> client.signDelegate(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.Stake.RedelegateParams -> client.signRedelegate(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.Stake.RewardsParams -> client.signRewards(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.Stake.UndelegateParams -> client.signUndelegate(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.Stake.WithdrawParams -> client.signWithdraw(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.SwapParams -> client.signSwap(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.TokenApprovalParams -> client.signTokenApproval(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.TransferParams.Generic -> client.signGenericTransfer(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.TransferParams.Native -> client.signNativeTransfer(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.TransferParams.Token -> client.signTokenTransfer(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.Activate -> client.signActivate(input, params.chainData, params.finalAmount, feePriority, privateKey) - is ConfirmParams.NftParams -> client.signNft(input, params.chainData, params.finalAmount, feePriority, privateKey) + is ConfirmParams.Stake.DelegateParams -> client.signDelegate(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.Stake.RedelegateParams -> client.signRedelegate(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.Stake.RewardsParams -> client.signRewards(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.Stake.UndelegateParams -> client.signUndelegate(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.Stake.WithdrawParams -> client.signWithdraw(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.SwapParams -> client.signSwap(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.TokenApprovalParams -> client.signTokenApproval(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.TransferParams.Generic -> client.signGenericTransfer(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.TransferParams.Native -> client.signNativeTransfer(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.TransferParams.Token -> client.signTokenTransfer(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.Activate -> client.signActivate(input, chainData, params.finalAmount, fee, privateKey) + is ConfirmParams.NftParams -> client.signNft(input, chainData, params.finalAmount, fee, privateKey) } } diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/SignerPreloaderProxy.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/SignerPreloaderProxy.kt new file mode 100644 index 000000000..2b646f5ca --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/SignerPreloaderProxy.kt @@ -0,0 +1,331 @@ +package com.gemwallet.android.blockchain.services + +import com.gemwallet.android.blockchain.clients.algorand.toChainData +import com.gemwallet.android.blockchain.clients.aptos.toChainData +import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinGatewayEstimateFee +import com.gemwallet.android.blockchain.clients.bitcoin.toChainData +import com.gemwallet.android.blockchain.clients.cardano.CardanoGatewayEstimateFee +import com.gemwallet.android.blockchain.clients.cardano.toChainData +import com.gemwallet.android.blockchain.clients.cosmos.toChainData +import com.gemwallet.android.blockchain.clients.ethereum.toChainData +import com.gemwallet.android.blockchain.clients.near.toChainData +import com.gemwallet.android.blockchain.clients.polkadot.PolkadotGatewayEstimateFee +import com.gemwallet.android.blockchain.clients.polkadot.toChainData +import com.gemwallet.android.blockchain.clients.solana.toChainData +import com.gemwallet.android.blockchain.clients.stellar.toChainData +import com.gemwallet.android.blockchain.clients.sui.toChainData +import com.gemwallet.android.blockchain.clients.ton.toChainData +import com.gemwallet.android.blockchain.clients.tron.toChainData +import com.gemwallet.android.blockchain.clients.xrp.toChainData +import com.gemwallet.android.blockchain.services.mapper.toGem +import com.gemwallet.android.domains.confirm.toGem +import com.gemwallet.android.domains.stake.toGem +import com.gemwallet.android.ext.toChainType +import com.gemwallet.android.model.ConfirmParams +import com.gemwallet.android.model.Fee +import com.gemwallet.android.model.GasFee +import com.gemwallet.android.model.SignerParams +import com.wallet.core.primitives.AssetId +import com.wallet.core.primitives.Chain +import com.wallet.core.primitives.ChainType +import com.wallet.core.primitives.FeePriority +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import uniffi.gemstone.GemApprovalData +import uniffi.gemstone.GemGasPriceType +import uniffi.gemstone.GemGateway +import uniffi.gemstone.GemGatewayEstimateFee +import uniffi.gemstone.GemStakeType +import uniffi.gemstone.GemTransactionInputType +import uniffi.gemstone.GemTransactionLoadFee +import uniffi.gemstone.GemTransactionLoadInput +import uniffi.gemstone.GemTransactionLoadMetadata +import uniffi.gemstone.GemTransactionPreloadInput +import uniffi.gemstone.GemTransferDataExtra +import uniffi.gemstone.GemTransferDataOutputType +import uniffi.gemstone.GemWalletConnectionSessionAppMetadata +import uniffi.gemstone.SwapperException + +class SignerPreloaderProxy( + private val gateway: GemGateway, +) { + + suspend fun preload(params: ConfirmParams): SignerParams = withContext(Dispatchers.IO) { + val assetId = params.assetId + val chain = assetId.chain + val feeAssetId = AssetId(chain) + val gemChain = assetId.chain.string + val destination = params.destination()?.address ?: throw java.lang.IllegalArgumentException() + + try { + val inputType = getInputType(params) + val metadata = gateway.getTransactionPreload( + chain = gemChain, + input = GemTransactionPreloadInput( + inputType = inputType, + senderAddress = params.from.address, + destinationAddress = destination + ) + ) + val feeRates = gateway.getFeeRates( + chain = gemChain, + input = inputType + ) + + val transactionData = feeRates.map { feeRate -> + val priority = FeePriority.entries.firstOrNull { it.string == feeRate.priority } ?: return@map null + + val result = gateway.getTransactionLoad( + chain = gemChain, + input = GemTransactionLoadInput( + inputType = inputType, + senderAddress = params.from.address, + destinationAddress = destination, + value = params.amount.toString(), + gasPrice = feeRate.gasPriceType, + memo = params.memo(), + isMaxValue = params.isMax(), + metadata = metadata, + ), + provider = getEstimateFee(chain) + ) + val fee = chain.toFeeType().convertFee(feeAssetId, priority, result.fee) + val chainData = result.metadata.toChainData() + SignerParams.Data(chainData = chainData, fee = fee) + }.filterNotNull() + + SignerParams( + input = params, + data = transactionData, + ) + } catch (err: Throwable) { + throw err + } + } + + private fun getInputType(params: ConfirmParams): GemTransactionInputType { + val gemAsset = params.asset.toGem() + val chain = params.assetId.chain.string + + return when (params) { + is ConfirmParams.Stake.DelegateParams -> GemTransactionInputType.Stake( + asset = gemAsset, + stakeType = GemStakeType.Delegate(params.validator.toGem(chain)) + ) + is ConfirmParams.Stake.RedelegateParams -> GemTransactionInputType.Stake( + asset = gemAsset, + stakeType = GemStakeType.Redelegate( + delegation = params.delegation.toGem(chain), + toValidator = params.dstValidator.toGem(chain) + ) + ) + is ConfirmParams.Stake.RewardsParams -> GemTransactionInputType.Stake( + asset = gemAsset, + stakeType = GemStakeType.WithdrawRewards( + validators = params.validators.map { it.toGem(chain) } + ) + ) + is ConfirmParams.Stake.UndelegateParams -> GemTransactionInputType.Stake( + asset = gemAsset, + stakeType = GemStakeType.Undelegate( + delegation = params.delegation.toGem(chain), + ) + ) + is ConfirmParams.Stake.WithdrawParams -> GemTransactionInputType.Stake( + asset = gemAsset, + stakeType = GemStakeType.Withdraw(params.delegation.toGem(chain)) + ) + is ConfirmParams.SwapParams -> GemTransactionInputType.Swap( + fromAsset = params.fromAsset.toGem(), + toAsset = params.toAsset.toGem(), + swapData = params.toGem(), + ) + is ConfirmParams.TokenApprovalParams -> GemTransactionInputType.TokenApprove( + gemAsset, + GemApprovalData( + params.assetId.tokenId!!, + spender = params.contract, + value = params.amount.toString(), + ) + ) + is ConfirmParams.TransferParams.Generic -> GemTransactionInputType.Generic( + asset = gemAsset, + metadata = GemWalletConnectionSessionAppMetadata( + name = params.name, + description = params.description, + url = params.url, + icon = params.icon, + redirectNative = params.redirectNative, + redirectUniversal = params.redirectUniversal, // TODO: Remove not used data + ), + extra = GemTransferDataExtra( + gasLimit = null, + gasPrice = null, + data = params.memo?.toByteArray(), + outputType = when (params.inputType) { + ConfirmParams.TransferParams.InputType.Signature -> GemTransferDataOutputType.SIGNATURE + ConfirmParams.TransferParams.InputType.EncodeTransaction -> GemTransferDataOutputType.ENCODED_TRANSACTION + null -> throw IllegalArgumentException("Not supported ${params.inputType}") + }, + ), + ) + is ConfirmParams.Activate, + is ConfirmParams.NftParams, + is ConfirmParams.TransferParams.Native, + is ConfirmParams.TransferParams.Token -> GemTransactionInputType.Transfer(gemAsset) + } + } + + private fun getEstimateFee(chain: Chain): GemGatewayEstimateFee { + return when (chain.toChainType()) { + ChainType.Bitcoin -> BitcoinGatewayEstimateFee() + ChainType.Cardano -> CardanoGatewayEstimateFee() + ChainType.Polkadot -> PolkadotGatewayEstimateFee() + ChainType.Ethereum, + ChainType.Solana, + ChainType.Cosmos, + ChainType.Ton, + ChainType.Tron, + ChainType.Aptos, + ChainType.Sui, + ChainType.Xrp, + ChainType.Near, + ChainType.Stellar, + ChainType.Algorand, + ChainType.HyperCore -> StubGatewayEstimateFee + } + } + + private object StubGatewayEstimateFee : GemGatewayEstimateFee { + override suspend fun getFee( + chain: uniffi.gemstone.Chain, + input: GemTransactionLoadInput + ): GemTransactionLoadFee? = null + + override suspend fun getFeeData( + chain: uniffi.gemstone.Chain, + input: GemTransactionLoadInput + ): String? = null + + } +} + +private sealed interface FeeType { + + fun convertFee(feeAssetId: AssetId, priority: FeePriority, gemFee: GemTransactionLoadFee): Fee + + object Plain : FeeType { + + override fun convertFee( + feeAssetId: AssetId, + priority: FeePriority, + gemFee: GemTransactionLoadFee + ): Fee { + return Fee( + feeAssetId = feeAssetId, + priority = priority, + amount = gemFee.fee.toBigInteger(), + options = gemFee.options.options.mapKeys { it.key.name }.mapValues { it.value.toBigInteger() } // TODO: Review keys + ) + } + + } + object Regular : FeeType { + + override fun convertFee( + feeAssetId: AssetId, + priority: FeePriority, + gemFee: GemTransactionLoadFee + ): Fee { + return GasFee( + feeAssetId = feeAssetId, + priority = priority, + maxGasPrice = (gemFee.gasPriceType as GemGasPriceType.Regular).gasPrice.toBigInteger(), + limit = gemFee.gasLimit.toBigInteger(), + amount = gemFee.fee.toBigInteger(), + options = gemFee.options.options.mapKeys { it.key.name }.mapValues { it.value.toBigInteger() } // TODO: Review keys + ) + } + + } + object Eip1559 : FeeType { + + override fun convertFee( + feeAssetId: AssetId, + priority: FeePriority, + gemFee: GemTransactionLoadFee + ): Fee { + return (gemFee.gasPriceType as GemGasPriceType.Eip1559).let { price -> + GasFee( + feeAssetId = feeAssetId, + priority = priority, + maxGasPrice = price.gasPrice.toBigInteger(), + minerFee = price.priorityFee.toBigInteger(), + limit = gemFee.gasLimit.toBigInteger(), + amount = gemFee.fee.toBigInteger(), + options = gemFee.options.options.mapKeys { it.key.name }.mapValues { it.value.toBigInteger() } // TODO: Change keys + ) + } + } + } + + object Solana : FeeType { + + override fun convertFee( + feeAssetId: AssetId, + priority: FeePriority, + gemFee: GemTransactionLoadFee + ): Fee { + return (gemFee.gasPriceType as GemGasPriceType.Solana).let { price -> + GasFee( + feeAssetId = feeAssetId, + priority = priority, + maxGasPrice = price.gasPrice.toBigInteger(), + minerFee = price.priorityFee.toBigInteger(), +// unitFee = price.unitPrice.toBigInteger(), + limit = gemFee.gasLimit.toBigInteger(), + amount = gemFee.fee.toBigInteger(), + options = gemFee.options.options.mapKeys { it.key.name }.mapValues { it.value.toBigInteger() } // TODO: Change keys + ) + } + } + + } +} + +private fun Chain.toFeeType() = when (this.toChainType()) { + ChainType.Solana -> FeeType.Solana + ChainType.Bitcoin, + ChainType.Cosmos, + ChainType.Aptos -> FeeType.Regular + ChainType.Ethereum -> FeeType.Eip1559 + ChainType.HyperCore, + ChainType.Ton, + ChainType.Tron, + ChainType.Sui, + ChainType.Xrp, + ChainType.Near, + ChainType.Stellar, + ChainType.Algorand, + ChainType.Polkadot, + ChainType.Cardano -> FeeType.Plain +} + +private fun GemTransactionLoadMetadata.toChainData() = when (this) { + is GemTransactionLoadMetadata.Algorand -> toChainData() + is GemTransactionLoadMetadata.Aptos -> toChainData() + is GemTransactionLoadMetadata.Bitcoin -> toChainData() + is GemTransactionLoadMetadata.Cardano -> toChainData() + is GemTransactionLoadMetadata.Cosmos -> toChainData() + is GemTransactionLoadMetadata.Evm -> toChainData() + is GemTransactionLoadMetadata.Near -> toChainData() + is GemTransactionLoadMetadata.Polkadot -> toChainData() + is GemTransactionLoadMetadata.Solana -> toChainData() + is GemTransactionLoadMetadata.Stellar -> toChainData() + is GemTransactionLoadMetadata.Sui -> toChainData() + is GemTransactionLoadMetadata.Ton -> toChainData() + is GemTransactionLoadMetadata.Tron -> toChainData() + is GemTransactionLoadMetadata.Xrp -> toChainData() + is GemTransactionLoadMetadata.Hyperliquid -> throw SwapperException.NotSupportedChain() + GemTransactionLoadMetadata.None -> throw SwapperException.NotSupportedChain() +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/StakeService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/StakeService.kt new file mode 100644 index 000000000..e6f670ff0 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/StakeService.kt @@ -0,0 +1,63 @@ +package com.gemwallet.android.blockchain.services + +import com.gemwallet.android.ext.toAssetId +import com.gemwallet.android.ext.toChain +import com.wallet.core.primitives.Chain +import com.wallet.core.primitives.DelegationBase +import com.wallet.core.primitives.DelegationState +import com.wallet.core.primitives.DelegationValidator +import uniffi.gemstone.GemGateway + +class StakeService( + private val gateway: GemGateway, +) { + suspend fun getValidators( + chain: Chain, + apr: Double + ): List { + return try { + val result = gateway.getStakingValidators( + chain = chain.string, + apr, + ) + result.mapNotNull { item -> + DelegationValidator( + chain = item.chain.toChain() ?: return@mapNotNull null, + id = item.id, + name = item.name, + isActive = item.isActive, + commision = item.commission, + apr = item.apr, + ) + } + } catch (_: Throwable) { + emptyList() + } + } + + suspend fun getStakeDelegations( + chain: Chain, + address: String, + ): List { + return try { + val result = gateway.getStakingDelegations( + chain = chain.string, + address, + ) + result.mapNotNull { item -> + DelegationBase( + assetId = item.assetId.toAssetId() ?: return@mapNotNull null, + state = DelegationState.entries.firstOrNull { it.string == item.delegationState } ?: return@mapNotNull null, + balance = item.balance, + rewards = item.rewards, + completionDate = item.completionDate?.toLong(), + delegationId = item.delegationId, + validatorId = item.validatorId, + shares = item.shares, + ) + } + } catch (_: Throwable) { + emptyList() + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/TokenService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/TokenService.kt new file mode 100644 index 000000000..5600bcf09 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/TokenService.kt @@ -0,0 +1,65 @@ +package com.gemwallet.android.blockchain.services + +import com.gemwallet.android.blockchain.services.mapper.toApp +import com.wallet.core.primitives.Asset +import com.wallet.core.primitives.AssetBasic +import com.wallet.core.primitives.AssetId +import com.wallet.core.primitives.AssetProperties +import com.wallet.core.primitives.AssetScore +import com.wallet.core.primitives.Chain +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.withContext +import uniffi.gemstone.GemGateway + +class TokenService( + private val gateway: GemGateway, +) { + suspend fun search(query: String) = withContext(Dispatchers.IO) { + Chain.entries.map { + async { + try { + if (gateway.getIsTokenAddress(it.string, query)) { + getTokenData(AssetId(it, query)) + } else { + null + } + } catch (_: Throwable) { + null + } + } + } + .awaitAll() + .filterNotNull() + .map { + AssetBasic( + asset = it, + score = AssetScore(0), + properties = AssetProperties( + isEnabled = false, + isBuyable = false, + isSellable = false, + isSwapable = false, + isStakeable = false + ) + ) + } + } + + suspend fun getTokenData(assetId: AssetId): Asset? { + val tokenId = assetId.tokenId ?: return null + val chain = assetId.chain + return try { + if (gateway.getIsTokenAddress(chain.string, tokenId)) { + val result = gateway.getTokenData(chain.string, tokenId) + result.toApp() + } else { + null + } + } catch (_: Throwable) { + null + } + + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/TransactionStatusService.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/TransactionStatusService.kt new file mode 100644 index 000000000..ec0c89a38 --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/TransactionStatusService.kt @@ -0,0 +1,40 @@ +package com.gemwallet.android.blockchain.services + +import com.gemwallet.android.blockchain.model.ServiceUnavailable +import com.gemwallet.android.blockchain.model.TransactionStateRequest +import com.gemwallet.android.model.HashChanges +import com.gemwallet.android.model.TransactionChanges +import com.wallet.core.primitives.TransactionState +import okhttp3.internal.toLongOrDefault +import uniffi.gemstone.GemGateway +import uniffi.gemstone.GemTransactionChange +import uniffi.gemstone.GemTransactionStateRequest + +class TransactionStatusService( + private val gateway: GemGateway, +) { + suspend fun getStatus(request: TransactionStateRequest): TransactionChanges? { + return try { + val result = gateway.getTransactionStatus( + chain = request.chain.string, + GemTransactionStateRequest( + id = request.hash, + senderAddress = request.sender, + createdAt = 0L, /// TODO: Add created at for HyperCore, + blockNumber = request.block.toLongOrDefault(0L) , + ) + ) + val fee = result.changes.firstNotNullOfOrNull { it as? GemTransactionChange.NetworkFee } + ?.v1?.toBigIntegerOrNull() + val hashChanges = result.changes.firstNotNullOfOrNull { it as? GemTransactionChange.HashChange } + + TransactionChanges( + state = TransactionState.entries.firstOrNull { it.string == result.state } ?: throw ServiceUnavailable, + fee = fee, + hashChanges = hashChanges?.let { HashChanges(it.old, it.new) } + ) + } catch (_: Throwable) { + throw ServiceUnavailable + } + } +} \ No newline at end of file diff --git a/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/mapper/Asset.kt b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/mapper/Asset.kt new file mode 100644 index 000000000..9d7e9db5e --- /dev/null +++ b/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/mapper/Asset.kt @@ -0,0 +1,34 @@ +package com.gemwallet.android.blockchain.services.mapper + +import com.gemwallet.android.ext.toAssetId +import com.gemwallet.android.ext.toIdentifier +import com.wallet.core.primitives.Asset +import com.wallet.core.primitives.AssetType +import com.wallet.core.primitives.UTXO +import uniffi.gemstone.GemAsset +import uniffi.gemstone.GemUtxo + +fun Asset.toGem() = GemAsset( + id = id.toIdentifier(), + name = name, + symbol = symbol, + decimals = decimals, + assetType = type.string, +) + +fun GemAsset.toApp() = Asset( + id = id.toAssetId()!!, + name = name, + symbol = symbol, + decimals = decimals, + type = AssetType.entries.firstOrNull { it.string == assetType }!! +) + +fun GemUtxo.toUtxo(): UTXO = UTXO( + transactionId, + vout.toInt(), + value, + address +) + +fun List.toUtxo() = map { it.toUtxo() } \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/Data.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/Data.kt deleted file mode 100644 index 28d099d92..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/Data.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.aptos.models.AptosAccount -import com.wallet.core.blockchain.aptos.AptosGasFee - -internal val aptosAccountResponse = AptosAccount( - sequence_number = "8", - message = null, - error_code = null, -) - -internal val aptosFeeResponse = AptosGasFee( - gas_estimate = 100, - prioritized_gas_estimate = 150, - deprioritized_gas_estimate = 250, -) \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBroadcast.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBroadcast.kt deleted file mode 100644 index 97dda3026..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosBroadcast.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.aptos.services.AptosBroadcastService -import com.gemwallet.android.math.decodeHex -import com.wallet.core.blockchain.aptos.AptosTransactionBroacast -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import junit.framework.TestCase.assertEquals -import kotlinx.coroutines.runBlocking -import okhttp3.RequestBody -import okio.Buffer -import org.junit.Test - -class TestAptosBroadcast { - - val sign: ByteArray = ("0x7b2265787069726174696f6e5f74696d657374616d705f73656373223a223336363" + - "4333930303832222c226761735f756e69745f7072696365223a22313530222c226d61785f6761735f616" + - "d6f756e74223a223138222c227061796c6f6164223a7b22617267756d656e7473223a5b2230783832313" + - "131663239373561306636303830643137383233363336396237343739663661656431323033656634613" + - "2336638323035653462393137313662373833222c223130303030303030303030225d2c2266756e63746" + - "96f6e223a223078313a3a6170746f735f6163636f756e743a3a7472616e73666572222c2274797065223" + - "a22656e7472795f66756e6374696f6e5f7061796c6f6164222c22747970655f617267756d656e7473223" + - "a5b5d7d2c2273656e646572223a223078396231646238313138306333316231623432383537326265313" + - "03565323039623561363232326237222c2273657175656e63655f6e756d626572223a2238222c2273696" + - "76e6174757265223a7b227075626c69635f6b6579223a223078633163343364356164646665316332333" + - "761646164363937326435663338663762393631353661636663366637656664386662346435333037653" + - "06365383861222c227369676e6174757265223a223078663063666439373630396263656639636661646" + - "239306264386566363565313432643862393039666537306137383539393434323330656234306566353" + - "061623236306130623931663935633632326364636537636637313835323365356565623532366433666" + - "1356438393635646431333966333637303930653562303031222c2274797065223a22656432353531395" + - "f7369676e6174757265227d7d").decodeHex() - val actualSendingData = "{" + - "\"expiration_timestamp_secs\":\"3664390082\"," + - "\"gas_unit_price\":\"150\"," + - "\"max_gas_amount\":\"18\"," + - "\"payload\":{" + - "\"arguments\":[\"0x82111f2975a0f6080d178236369b7479f6aed1203ef4a23f8205e4b91716b783\",\"10000000000\"]," + - "\"function\":\"0x1::aptos_account::transfer\",\"type\":\"entry_function_payload\",\"type_arguments\":[]}," + - "\"sender\":\"0x9b1db81180c31b1b428572be105e209b5a6222b7\"," + - "\"sequence_number\":\"8\"," + - "\"signature\":{" + - "\"public_key\":\"0xc1c43d5addfe1c237adad6972d5f38f7b96156acfc6f7efd8fb4d5307e0ce88a\"," + - "\"signature\":\"0xf0cfd97609bcef9cfadb90bd8ef65e142d8b909fe70a7859944230eb40ef50ab260a0b91f95c622cdce7cf718523e5eeb526d3fa5d8965dd139f367090e5b001\"," + - "\"type\":\"ed25519_signature\"}}" - - @Test - fun testAptosBroadcast() { - var sendingData: String = "" - val broadcastClient = AptosBroadcastClient( - Chain.Aptos, - object : AptosBroadcastService { - override suspend fun broadcast(request: RequestBody): Result { - assertEquals(Mime.Json.value, request.contentType()) - val buffer = Buffer() - request.writeTo(buffer) - sendingData = String(buffer.inputStream().readAllBytes()) - return Result.success( - AptosTransactionBroacast(hash = "some hash") - ) - } - } - - ) - val result = runBlocking { - broadcastClient.send( - Account(Chain.Aptos, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - sign, - TransactionType.Transfer, - ) - } - - assertEquals(actualSendingData, sendingData) - assertEquals("some hash", result) - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosFeeCalculator.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosFeeCalculator.kt deleted file mode 100644 index bdfedfa74..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosFeeCalculator.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.aptos.models.AptosAccount -import com.gemwallet.android.blockchain.clients.aptos.services.AptosAccountsService -import com.gemwallet.android.blockchain.clients.aptos.services.AptosFeeService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.wallet.core.blockchain.aptos.AptosGasFee -import com.wallet.core.blockchain.aptos.AptosTransaction -import com.wallet.core.blockchain.aptos.AptosTransactionSimulation -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestAptosFeeCalculator { - @Test - fun testAptosFeeAccountError() { - val preloader = AptosSignerPreloader( - chain = Chain.Aptos, - accountsService = object : AptosAccountsService { - override suspend fun accounts(address: String): Result { - return Result.success(aptosAccountResponse.copy(sequence_number = null, error_code = null, message = "Error message")) - } - - }, - feeService = object : AptosFeeService { - override suspend fun feePrice(): Result { - return Result.success(aptosFeeResponse) - } - - override suspend fun simulate(data: AptosTransactionSimulation): Result> { - return Result.success(listOf(AptosTransaction(true, "69", "0"))) - } - } - ) - try { - runBlocking { - preloader.preloadNativeTransfer( - params = ConfirmParams.TransferParams.Native( - asset = Chain.Aptos.asset(), - from = Account(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", ""), - amount = BigInteger.valueOf(10_000_000_000), - destination = DestinationAddress("0xd7257c62806cea85fc8eaf947377b672fe062b81e6c0b19b6d8a3f408e59cf8c"), - isMaxAmount = false - ) - ) - } - assertTrue(false) - } catch (err: Throwable) { - assertEquals(null, err.message) - } - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSignerPreloader.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSignerPreloader.kt deleted file mode 100644 index 19c554353..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosSignerPreloader.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.aptos.models.AptosAccount -import com.gemwallet.android.blockchain.clients.aptos.services.AptosAccountsService -import com.gemwallet.android.blockchain.clients.aptos.services.AptosFeeService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.toIdentifier -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.gemwallet.android.model.GasFee -import com.wallet.core.blockchain.aptos.AptosGasFee -import com.wallet.core.blockchain.aptos.AptosTransaction -import com.wallet.core.blockchain.aptos.AptosTransactionSimulation -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestAptosSignerPreloader { - - @Test - fun testAptosPreload() { - var serviceAddressParam = mutableListOf() - val preloader = AptosSignerPreloader( - chain = Chain.Aptos, - accountsService = object : AptosAccountsService { - override suspend fun accounts(address: String): Result { - serviceAddressParam.add(address) - return Result.success(aptosAccountResponse) - } - - }, - feeService = object : AptosFeeService { - override suspend fun feePrice(): Result { - return Result.success(aptosFeeResponse) - } - - override suspend fun simulate(data: AptosTransactionSimulation): Result> { - return Result.success(listOf(AptosTransaction(true, "9", "0"))) - } - } - ) - val result = runBlocking { - preloader.preloadNativeTransfer( - params = ConfirmParams.TransferParams.Native( - asset = Chain.Aptos.asset(), - from = Account(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", ""), - amount = BigInteger.valueOf(10_000_000_000), - destination = DestinationAddress("0xd7257c62806cea85fc8eaf947377b672fe062b81e6c0b19b6d8a3f408e59cf8c"), - isMaxAmount = false - ) - ) - } - assertEquals("0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", serviceAddressParam[0]) -// assertEquals("0xd7257c62806cea85fc8eaf947377b672fe062b81e6c0b19b6d8a3f408e59cf8c", serviceAddressParam[1]) - assertEquals(BigInteger.valueOf(10_000_000_000), result.input.amount) - assertEquals("0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", result.input.from.address) - assertEquals(AssetId(Chain.Aptos).toIdentifier(), result.input.assetId.toIdentifier()) - assertEquals(false, result.input.isMax()) - assertEquals("0xd7257c62806cea85fc8eaf947377b672fe062b81e6c0b19b6d8a3f408e59cf8c", result.input.destination()?.address) - assertEquals(null, result.input.memo()) - assertEquals(BigInteger.valueOf(1350L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(150L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(9), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Aptos).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(8L, (result.chainData as AptosSignerPreloader.AptosChainData).sequence) - } - - @Test - fun testAptosEmptyAccountPreload() { - val preloader = AptosSignerPreloader( - chain = Chain.Aptos, - accountsService = object : AptosAccountsService { - override suspend fun accounts(address: String): Result { - return Result.success(aptosAccountResponse.copy(sequence_number = null, error_code = "account_not_found")) - } - - }, - feeService = object : AptosFeeService { - override suspend fun feePrice(): Result { - return Result.success(aptosFeeResponse) - } - - override suspend fun simulate(data: AptosTransactionSimulation): Result> { - return Result.success(listOf(AptosTransaction(true, "9", "0"))) - } - } - ) - val result = runBlocking { - preloader.preloadNativeTransfer( - params = ConfirmParams.TransferParams.Native( - asset = Chain.Aptos.asset(), - from = Account(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", ""), - amount = BigInteger.valueOf(10_000_000_000), - destination = DestinationAddress("0xd7257c62806cea85fc8eaf947377b672fe062b81e6c0b19b6d8a3f408e59cf8c"), - isMaxAmount = false - ) - ) - } - assertEquals(BigInteger.valueOf(1350L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(150L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(9L), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Aptos).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(0L, (result.chainData as AptosSignerPreloader.AptosChainData).sequence) - } - - @Test - fun testAptosFeeFail() { - val preloader = AptosSignerPreloader( - chain = Chain.Aptos, - accountsService = object : AptosAccountsService { - override suspend fun accounts(address: String): Result { - return Result.success(aptosAccountResponse.copy(sequence_number = null, error_code = null, message = "Message")) - } - - }, - feeService = object : AptosFeeService { - override suspend fun feePrice(): Result { - return Result.success(aptosFeeResponse) - } - - override suspend fun simulate(data: AptosTransactionSimulation): Result> { - return Result.success(listOf(AptosTransaction(true, "0", "69"))) - } - } - ) - try { - runBlocking { - preloader.preloadNativeTransfer( - params = ConfirmParams.TransferParams.Native( - asset = Chain.Aptos.asset(), - from = Account(Chain.Aptos, "0x80c3cca35602e4568a7ac88d4d91110f8efa6c45c659439c2b4ed04033059c6f", ""), - amount = BigInteger.valueOf(10_000_000_000), - destination = DestinationAddress("0xd7257c62806cea85fc8eaf947377b672fe062b81e6c0b19b6d8a3f408e59cf8c"), - isMaxAmount = false - ) - ) - } - assertTrue(false) - } catch (err: Throwable) { - assertEquals(null, err.message) - } - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosTransactions.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosTransactions.kt deleted file mode 100644 index fabcdd6e2..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/aptos/TestAptosTransactions.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.gemwallet.android.blockchain.clients.aptos - -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.aptos.services.AptosTransactionsService -import com.wallet.core.blockchain.aptos.AptosTransaction -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestAptosTransactions { - - @Test - fun testAptosTransaction() { - var requestId: String = "" - val transactionsClient = AptosTransactionStatusClient( - Chain.Aptos, - object : AptosTransactionsService { - override suspend fun transactions(txId: String): Result { - requestId = txId - return Result.success( - AptosTransaction( - success = true, - gas_used = "100", - gas_unit_price = "10" - ) - ) - } - } - ) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Aptos, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals("some_id", requestId) - assertEquals(TransactionState.Confirmed, result.state) - assertEquals(BigInteger("1000"), result.fee) - } - - @Test - fun testAptosTransactionFail() { - var requestId: String = "" - val transactionsClient = AptosTransactionStatusClient( - Chain.Aptos, - object : AptosTransactionsService { - override suspend fun transactions(txId: String): Result { - requestId = txId - return Result.success( - AptosTransaction( - success = false, - gas_used = "100", - gas_unit_price = "10" - ) - ) - } - } - ) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Aptos, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals(TransactionState.Reverted, result.state) - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinBroadcast.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinBroadcast.kt deleted file mode 100644 index 09965e574..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinBroadcast.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinBroadcastService -import com.gemwallet.android.math.decodeHex -import com.wallet.core.blockchain.bitcoin.BitcoinTransactionBroacastResult -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import junit.framework.TestCase.assertEquals -import kotlinx.coroutines.runBlocking -import okhttp3.RequestBody -import okio.Buffer -import org.junit.Test - -class TestBitcoinBroadcast { - - val sign = "010000000153bd8a94cf6424d8e54cacbad6082c249cdacdd0956f766206a" + - "c3daed5e5479f010000006b483045022100ead2b7637532b167e66ddf76eafd032ada898c8719a" + - "680de8183b71fb3086a3e022055a073be9148cb8b9dc71de04755dbf11f140fee167ed0d4b44d6" + - "a54a829e75e012102fd6585adc0e86019abf00e83552d054cb5f4359ad4db8ca338099381f43e2" + - "5a5000000000182a82005000000001976a91424849c1d94eb9e6e002dd75fdcbce0a9673daba78" + - "8ac00000000" - - @Test - fun testBitcoinBroadcast() { - var sendingData: String = "" - val broadcastClient = BitcoinBroadcastClient( - Chain.Bitcoin, - object : BitcoinBroadcastService { - override suspend fun broadcast(request: RequestBody): Result { - assertEquals(Mime.Plain.value, request.contentType()) - val buffer = Buffer() - request.writeTo(buffer) - sendingData = String(buffer.inputStream().readAllBytes()) - return Result.success( - BitcoinTransactionBroacastResult(result = "some hash") - ) - } - } - - ) - val result = runBlocking { - broadcastClient.send( - Account(Chain.Bitcoin, "0x9b1DB81180c31B1b428572Be105E209b5A6222b7", ""), - sign.decodeHex(), - TransactionType.Transfer, - ) - } - - assertEquals(sign, sendingData) - assertEquals("some hash", result) - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinTransactions.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinTransactions.kt deleted file mode 100644 index 8936c33cc..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/bitcoin/TestBitcoinTransactions.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.gemwallet.android.blockchain.clients.bitcoin - -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinTransactionsService -import com.wallet.core.blockchain.bitcoin.BitcoinTransaction -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import kotlinx.coroutines.runBlocking -import org.junit.Test - -class TestBitcoinTransactions { - - @Test - fun testBitcoinTransaction() { - var requestId = "" - val transactionsClient = BitcoinTransactionStatusClient( - Chain.Bitcoin, - object : BitcoinTransactionsService { - override suspend fun transaction(txId: String): Result { - requestId = txId - return Result.success(BitcoinTransaction(0)) - } - } - ) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Bitcoin, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals("some_id", requestId) - assertEquals(TransactionState.Pending, result.state) - } - - @Test - fun testBitcoinTransactionConfirm() { - var requestId = "" - val transactionsClient = BitcoinTransactionStatusClient( - Chain.Bitcoin, - object : BitcoinTransactionsService { - override suspend fun transaction(txId: String): Result { - requestId = txId - return Result.success(BitcoinTransaction(1)) - } - } - ) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Bitcoin, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals(TransactionState.Confirmed, result.state) - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosBroadcast.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosBroadcast.kt deleted file mode 100644 index 37f1e242f..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosBroadcast.kt +++ /dev/null @@ -1,109 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.Mime -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosBroadcastService -import com.gemwallet.android.math.decodeHex -import com.wallet.core.blockchain.cosmos.CosmosBroadcastResponse -import com.wallet.core.blockchain.cosmos.CosmosBroadcastResult -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionType -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import okhttp3.RequestBody -import okio.Buffer -import org.junit.Test - -class TestCosmosBroadcast { - - val sign = "0x7b226d6f6465223a2242524f4144434153545f4d4f44455f53594e43222c2274785f6279746573223" + - "a22436f6f42436f6342436877765932397a6257397a4c6d4a68626d7375646a46695a585268" + - "4d53354e633264545a57356b456d634b4b32397a62573878613264735a57313162585534625" + - "734324e5468714e6d6330656a6c71656d347a656d566d4d6e466b65586c326132783359544d" + - "534b32397a62573878636d4e71646e70364f486436613352785a6e6f346357706d4d4777356" + - "354513161337034646d5177656a42754e3277315932596143776f466457397a62573853416a" + - "4577456d674b55417047436838765932397a6257397a4c6d4e79655842306279357a5a574e7" + - "74d6a5532617a4575554856695332563545694d4b49514d736c63596e374468506535622f38" + - "6c4d33466e50586847426a3553644331352b584931685a31675962424249454367494941526" + - "74b4568514b44676f466457397a62573853425445774d444177454d436144427041564a6b44" + - "786153355a6167686d4a365a7470433979696d374a413864754f384d774f4f44644a6548454" + - "87373483350514e2b34596c2b5356794c744e4557362b4944554b666b4731646649594f7670" + - "5269466c4f79673d3d227d" - - @Test - fun testCosmosBroadcast() { - var sendingData: String = "" - val broadcastClient = CosmosBroadcastClient( - Chain.Cosmos, - object : CosmosBroadcastService { - override suspend fun broadcast(request: RequestBody): Result { - assertEquals(Mime.Json.value, request.contentType()) - val buffer = Buffer() - request.writeTo(buffer) - sendingData = String(buffer.inputStream().readAllBytes()) - return Result.success( - CosmosBroadcastResponse( - CosmosBroadcastResult( - txhash = "some hash", - code = 0, - raw_log = "" - ) - ) - ) - } - } - - ) - val result = runBlocking { - broadcastClient.send( - Account(Chain.Cosmos, "cosmos1kglemumu8mn658j6g4z9jzn3zef2qdyyydv7tr", ""), - sign.decodeHex(), - TransactionType.Transfer, - ) - } - - assertEquals( - "{\"mode\":\"BROADCAST_MODE_SYNC\",\"tx_bytes\":\"CooBCocBChwvY29zbW9zLmJhb" + - "msudjFiZXRhMS5Nc2dTZW5kEmcKK29zbW8xa2dsZW11bXU4bW42NThqNmc0ejlqem4zemVmMnFkeXl2" + - "a2x3YTMSK29zbW8xcmNqdnp6OHd6a3RxZno4cWpmMGw5cTQ1a3p4dmQwejBuN2w1Y2YaCwoFdW9zbW8" + - "SAjEwEmgKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQMslcYn7DhPe5b/8l" + - "M3FnPXhGBj5SdC15+XI1hZ1gYbBBIECgIIARgKEhQKDgoFdW9zbW8SBTEwMDAwEMCaDBpAVJkDxaS5Z" + - "aghmJ6ZtpC9yim7JA8duO8MwOODdJeHEHssH3PQN+4Yl+SVyLtNEW6+IDUKfkG1dfIYOvpRiFlOyg==\"}", - sendingData - ) - assertEquals("some hash", result) - } - - @Test - fun testCosmosBroadcastFail() { - var sendingData: String = "" - val broadcastClient = CosmosBroadcastClient( - Chain.Cosmos, - object : CosmosBroadcastService { - override suspend fun broadcast(request: RequestBody): Result { - assertEquals(Mime.Json.value, request.contentType()) - val buffer = Buffer() - request.writeTo(buffer) - sendingData = String(buffer.inputStream().readAllBytes()) - return Result.success( - CosmosBroadcastResponse(CosmosBroadcastResult(txhash = "some hash", code = 1, raw_log = "Some error")) - ) - } - } - - ) - try { - val result = runBlocking { - broadcastClient.send( - Account(Chain.Cosmos, "cosmos1kglemumu8mn658j6g4z9jzn3zef2qdyyydv7tr", ""), - sign.decodeHex(), - TransactionType.Transfer, - ) - } - assertTrue(false) - } catch (err: Throwable) { - assertEquals("Some error", err.message) - } - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosPreload.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosPreload.kt deleted file mode 100644 index 42dc452d3..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosPreload.kt +++ /dev/null @@ -1,189 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosAccountsService -import com.gemwallet.android.ext.asset -import com.gemwallet.android.ext.toIdentifier -import com.gemwallet.android.model.ConfirmParams -import com.gemwallet.android.model.DestinationAddress -import com.gemwallet.android.model.GasFee -import com.wallet.core.blockchain.cosmos.CosmosAccount -import com.wallet.core.blockchain.cosmos.CosmosAccountResponse -import com.wallet.core.blockchain.cosmos.CosmosBlock -import com.wallet.core.blockchain.cosmos.CosmosBlockResponse -import com.wallet.core.blockchain.cosmos.CosmosHeader -import com.wallet.core.blockchain.cosmos.CosmosInjectiveAccount -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.FeePriority -import junit.framework.TestCase.assertEquals -import kotlinx.coroutines.runBlocking -import org.junit.Test -import java.math.BigInteger - -class TestCosmosPreload { - - private val accountsService = object : CosmosAccountsService { - - var addressRequest: String = "" - - override suspend fun getAccountData(owner: String): Result> { - addressRequest = owner - return Result.success(CosmosAccountResponse(CosmosAccount(account_number = "2913388", sequence = "10"))) - } - - override suspend fun getInjectiveAccountData(owner: String): Result> { - throw Exception() - } - - override suspend fun getNodeInfo(): Result { - return Result.success(CosmosBlockResponse( - CosmosBlock( - CosmosHeader( - chain_id = "osmosis-1", - height = "25181150" - ) - ) - )) - } - } - - - @Test - fun testCosmosPreload() { - val preload = CosmosSignerPreloader(Chain.Osmosis, accountsService) - val result = runBlocking { - preload.preloadNativeTransfer( - ConfirmParams.TransferParams.Native( - from = Account(Chain.Osmosis, "osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", ""), - amount = BigInteger.ONE, - asset = Chain.Osmosis.asset(), - destination = DestinationAddress("osmo1rcjvzz8wzktqfz8qjf0l9q45kzxvd0z0n7l5cf"), - ) - ) - } - assertEquals("osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", accountsService.addressRequest) - - assertEquals(BigInteger.valueOf(1), result.input.amount) - assertEquals("osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", result.input.from.address) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.input.assetId.toIdentifier()) - assertEquals(false, result.input.isMax()) - assertEquals("osmo1rcjvzz8wzktqfz8qjf0l9q45kzxvd0z0n7l5cf", result.input.destination()?.address) - assertEquals(null, result.input.memo()) - - assertEquals(BigInteger.valueOf(10000L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(10000L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(200000L), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(10L, (result.chainData as CosmosSignerPreloader.CosmosChainData).sequence) - assertEquals(2913388L, (result.chainData as CosmosSignerPreloader.CosmosChainData).accountNumber) - assertEquals("osmosis-1", (result.chainData as CosmosSignerPreloader.CosmosChainData).chainId) - } - - @Test - fun testCosmosDelegatePreload() { - val preload = CosmosSignerPreloader(Chain.Osmosis, accountsService) - val result = runBlocking { - preload.preloadStake( - ConfirmParams.Stake.DelegateParams( - from = Account(Chain.Osmosis, "osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", ""), - amount = BigInteger.ONE, - asset = Chain.Osmosis.asset(), - validatorId = "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm" - ) - ) - } - - assertEquals("osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", accountsService.addressRequest) - assertEquals(BigInteger.valueOf(100000L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(100000L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(1000000L), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(10L, (result.chainData as CosmosSignerPreloader.CosmosChainData).sequence) - assertEquals(2913388L, (result.chainData as CosmosSignerPreloader.CosmosChainData).accountNumber) - assertEquals("osmosis-1", (result.chainData as CosmosSignerPreloader.CosmosChainData).chainId) - } - - @Test - fun testCosmosUndelegatePreload() { - val preload = CosmosSignerPreloader(Chain.Osmosis, accountsService) - val result = runBlocking { - preload.preloadStake( - ConfirmParams.Stake.UndelegateParams( - from = Account(Chain.Osmosis, "osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", ""), - amount = BigInteger.ONE, - asset = Chain.Osmosis.asset(), - validatorId = "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - delegationId = "25053096", - share = "", - balance = "2000000", - ) - ) - } - assertEquals("osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", accountsService.addressRequest) - assertEquals(BigInteger.valueOf(100000L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(100000L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(1000000L), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(10L, (result.chainData as CosmosSignerPreloader.CosmosChainData).sequence) - assertEquals(2913388L, (result.chainData as CosmosSignerPreloader.CosmosChainData).accountNumber) - assertEquals("osmosis-1", (result.chainData as CosmosSignerPreloader.CosmosChainData).chainId) - } - - @Test - fun testCosmosRedelegatePreload() { - val preload = CosmosSignerPreloader(Chain.Osmosis, accountsService) - val result = runBlocking { - preload.preloadStake( - ConfirmParams.Stake.RedelegateParams( - from = Account(Chain.Osmosis, "osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", ""), - amount = BigInteger.ONE, - asset = Chain.Osmosis.asset(), - srcValidatorId = "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - dstValidatorId = "osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", - share = "", - balance = "2000000", - ) - ) - } - assertEquals("osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", accountsService.addressRequest) - assertEquals(BigInteger.valueOf(100000L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(100000L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(1250000L), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(10L, (result.chainData as CosmosSignerPreloader.CosmosChainData).sequence) - assertEquals(2913388L, (result.chainData as CosmosSignerPreloader.CosmosChainData).accountNumber) - assertEquals("osmosis-1", (result.chainData as CosmosSignerPreloader.CosmosChainData).chainId) - } - - @Test - fun testCosmosRewardsPreload() { - val preload = CosmosSignerPreloader(Chain.Osmosis, accountsService) - val result = runBlocking { - preload.preloadStake( - ConfirmParams.Stake.RewardsParams( - from = Account(Chain.Osmosis, "osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", ""), - amount = BigInteger.ONE, - asset = Chain.Osmosis.asset(), - validatorsId = listOf( - "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - "osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", - ), - ) - ) - } - assertEquals("osmo1q0d0q8w8y8t6h4l9w5u8p8s8h8f8e8r8t8y8u8i8o8p8", accountsService.addressRequest) - assertEquals(BigInteger.valueOf(100000L), result.chainData.fee().amount) - assertEquals(BigInteger.valueOf(100000L), (result.chainData.fee() as GasFee).maxGasPrice) - assertEquals(BigInteger.valueOf(900000L), (result.chainData.fee() as GasFee).limit) - assertEquals(AssetId(Chain.Osmosis).toIdentifier(), result.chainData.fee().feeAssetId.toIdentifier()) - assertEquals(FeePriority.Normal, result.chainData.fee().priority) - assertEquals(10L, (result.chainData as CosmosSignerPreloader.CosmosChainData).sequence) - assertEquals(2913388L, (result.chainData as CosmosSignerPreloader.CosmosChainData).accountNumber) - assertEquals("osmosis-1", (result.chainData as CosmosSignerPreloader.CosmosChainData).chainId) - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosStake.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosStake.kt deleted file mode 100644 index 2086d86f6..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosStake.kt +++ /dev/null @@ -1,179 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosStakeService -import com.wallet.core.blockchain.cosmos.CosmosBalance -import com.wallet.core.blockchain.cosmos.CosmosDelegation -import com.wallet.core.blockchain.cosmos.CosmosDelegationData -import com.wallet.core.blockchain.cosmos.CosmosDelegations -import com.wallet.core.blockchain.cosmos.CosmosReward -import com.wallet.core.blockchain.cosmos.CosmosRewards -import com.wallet.core.blockchain.cosmos.CosmosUnboudingDelegationEntry -import com.wallet.core.blockchain.cosmos.CosmosUnboundingDelegation -import com.wallet.core.blockchain.cosmos.CosmosUnboundingDelegations -import com.wallet.core.blockchain.cosmos.CosmosValidator -import com.wallet.core.blockchain.cosmos.CosmosValidatorCommission -import com.wallet.core.blockchain.cosmos.CosmosValidatorCommissionRates -import com.wallet.core.blockchain.cosmos.CosmosValidatorMoniker -import com.wallet.core.blockchain.cosmos.CosmosValidators -import com.wallet.core.primitives.AssetId -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.DelegationState -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertFalse -import junit.framework.TestCase.assertNull -import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.runBlocking -import org.junit.Test - -class TestCosmosStake { - - private class TestCosmosStakeService( - val validators: List = listOf( - CosmosValidator( - operator_address = "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - jailed = false, - status = "BOND_STATUS_BONDED", - description = CosmosValidatorMoniker("stakebeast"), - commission = CosmosValidatorCommission(CosmosValidatorCommissionRates(rate = "0.050000000000000000")) - ), - CosmosValidator( - operator_address = "osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", - jailed = false, - status = "BOND_STATUS_UBONDED", - description = CosmosValidatorMoniker("Redline Validation"), - commission = CosmosValidatorCommission(CosmosValidatorCommissionRates(rate = "1.000000000000000000")) - ), - CosmosValidator( - operator_address = "osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q", - jailed = true, - status = "BOND_STATUS_UNBONDED", - description = CosmosValidatorMoniker("Dystopia Labs Validator"), - commission = CosmosValidatorCommission(CosmosValidatorCommissionRates(rate = "0.040000000000000000")) - ), - CosmosValidator( - operator_address = "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - jailed = false, - status = "BOND_STATUS_BONDED", - description = CosmosValidatorMoniker("Cypher Core"), - commission = CosmosValidatorCommission(CosmosValidatorCommissionRates(rate = "0.100000000000000000")) - ), - ), - val delegations: List = emptyList(), - val unboundings: List = emptyList(), - val rewards: List = emptyList(), - ) : CosmosStakeService { - - var delegationsAddressRequest: String = "" - var unboundingAddressRequest: String = "" - var rewardsAddressRequest: String = "" - - override suspend fun validators(): Result { - return Result.success(CosmosValidators(validators)) - } - - override suspend fun delegations(address: String): Result { - delegationsAddressRequest = address - return Result.success(CosmosDelegations(delegations)) - } - - override suspend fun undelegations(address: String): Result { - unboundingAddressRequest = address - return Result.success(CosmosUnboundingDelegations(unboundings)) - } - - override suspend fun rewards(address: String): Result { - rewardsAddressRequest = address - return Result.success(CosmosRewards(rewards)) - } - - } - - @Test - fun testGetValidators() { - val client = CosmosStakeClient( - chain = Chain.Osmosis, - stakeService = TestCosmosStakeService() - ) - val result = runBlocking { client.getValidators(Chain.Osmosis, 5.68) } - assertFalse(result.isEmpty()) - assertEquals(4, result.size) - for (validator in result) { - assertEquals(Chain.Osmosis, validator.chain) - } - assertTrue(result[0].isActive) - assertFalse(result[1].isActive) - assertFalse(result[2].isActive) - assertTrue(result[3].isActive) - assertEquals("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", result[0].id) - assertEquals("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", result[1].id) - assertEquals("Redline Validation", result[1].name) - assertEquals("Cypher Core", result[3].name) - assertEquals(0.05, result[0].commision) - assertEquals(0.04, result[2].commision) - assertEquals(5.396, result[0].apr) - assertEquals(5.112, result[3].apr) - } - - @Test - fun testGetValidatorsEmpty() { - val client = CosmosStakeClient( - chain = Chain.Osmosis, - stakeService = TestCosmosStakeService(emptyList()) - ) - val result = runBlocking { client.getValidators(Chain.Osmosis, 5.68) } - assertTrue(result.isEmpty()) - } - - @Test - fun testGetDelegations() { - val client = CosmosStakeClient( - Chain.Osmosis, - TestCosmosStakeService( - delegations = listOf( - CosmosDelegation( - CosmosDelegationData("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm"), - CosmosBalance("uosmo", "1000000") - ), - CosmosDelegation( - CosmosDelegationData("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2"), - CosmosBalance("uosmo", "1000000") - ), - CosmosDelegation( - CosmosDelegationData("osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q"), - CosmosBalance("uosmo", "721000000") - ) - ), - unboundings = listOf( - CosmosUnboundingDelegation( - "osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", - entries = listOf( - CosmosUnboudingDelegationEntry( - creation_height = "25053096", - completion_time = "2024-12-18T02:11:27.650773866Z", - balance = "2000000", - ) - ) - ), - ), - rewards = listOf( - CosmosReward("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", listOf(CosmosBalance(denom = "uosmo", amount = "808.015913259210000000"))), - CosmosReward("osmovaloper1z0sh4s80u99l6y9d3vfy582p8jejeeu6tcucs2", listOf(CosmosBalance(denom = "uosmo", amount = "808.009961413523000000"))), - CosmosReward("osmovaloper1wgmdcxzp49vjgrqusgcagq6qefk4mtjv5c0k7q", listOf(CosmosBalance(denom = "uosmo", amount = "582579.692713670953000000"))), - ) - ) - ) - val result = runBlocking { client.getStakeDelegations(Chain.Osmosis, "osmo1ac4ns740p4v78n4wr7j3t3s79jjjre6udx7n2v", 5.68) } - assertEquals(4, result.size) - assertEquals(AssetId(Chain.Osmosis), result[0].assetId) - assertEquals(DelegationState.Active, result[0].state) - assertEquals(DelegationState.Pending, result[3].state) - assertEquals("1000000", result[0].balance) - assertEquals("2000000", result[3].balance) - assertEquals("808", result[0].rewards) - assertEquals("808", result[3].rewards) - assertNull(result[0].completionDate) - assertEquals(1735138660866, result[3].completionDate) - assertEquals("", result[0].delegationId) - assertEquals("osmovaloper1pxphtfhqnx9ny27d53z4052e3r76e7qq495ehm", result[0].validatorId) - } -} \ No newline at end of file diff --git a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosTransactions.kt b/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosTransactions.kt deleted file mode 100644 index facf07fc9..000000000 --- a/blockchain/src/test/kotlin/com/gemwallet/android/blockchain/clients/cosmos/TestCosmosTransactions.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.gemwallet.android.blockchain.clients.cosmos - -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosTransactionsService -import com.wallet.core.blockchain.cosmos.CosmosTransactionDataResponse -import com.wallet.core.blockchain.cosmos.CosmosTransactionResponse -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.TransactionState -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import kotlinx.coroutines.runBlocking -import org.junit.Test - -class TestCosmosTransactions { - - @Test - fun testCosmosTransaction() { - var requestId = "" - val transactionsService = object : CosmosTransactionsService { - override suspend fun transaction(txId: String): Result { - requestId = txId - return Result.success( - CosmosTransactionResponse( - CosmosTransactionDataResponse( - txId, - 0 - ) - ) - ) - } - - } - val transactionsClient = CosmosTransactionStatusClient(Chain.Osmosis, transactionsService) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Cosmos, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals("some_id", requestId) - assertEquals(TransactionState.Confirmed, result.state) - } - - @Test - fun testCosmosTransactionPending() { - val transactionsService = object : CosmosTransactionsService { - override suspend fun transaction(txId: String): Result { - return Result.success(CosmosTransactionResponse(CosmosTransactionDataResponse("", 0))) - } - - } - val transactionsClient = CosmosTransactionStatusClient(Chain.Osmosis, transactionsService) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Cosmos, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals(TransactionState.Pending, result.state) - } - - @Test - fun testCosmosTransactionReverted() { - val transactionsService = object : CosmosTransactionsService { - override suspend fun transaction(txId: String): Result { - return Result.success(CosmosTransactionResponse(CosmosTransactionDataResponse(txId, 1))) - } - - } - val transactionsClient = CosmosTransactionStatusClient(Chain.Osmosis, transactionsService) - val result = runBlocking { - transactionsClient.getStatus( - TransactionStateRequest( - Chain.Cosmos, - "some_id", - "", - "some_address", - ) - ) - } - assertNotNull(result) - assertEquals(TransactionState.Reverted, result.state) - } -} \ No newline at end of file diff --git a/core b/core index 954c53d40..e4c7e6686 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 954c53d40dfd57f5ee311413fbd630313e2cb577 +Subproject commit e4c7e6686a9e3b60559eb474ad809bb8acb6b3d0 diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/AssetsRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/AssetsRepository.kt index f458ee511..0d76c43d5 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/AssetsRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/AssetsRepository.kt @@ -1,6 +1,7 @@ package com.gemwallet.android.data.repositoreis.assets import com.gemwallet.android.blockchain.operators.GetAsset +import com.gemwallet.android.blockchain.services.BalancesService import com.gemwallet.android.cases.device.GetDeviceIdCase import com.gemwallet.android.cases.tokens.SearchTokensCase import com.gemwallet.android.cases.transactions.GetTransactions @@ -71,7 +72,7 @@ class AssetsRepository @Inject constructor( private val pricesDao: PricesDao, private val gemApi: GemApiClient, private val sessionRepository: SessionRepository, - private val balancesRemoteSource: BalancesRemoteSource, + private val balancesService: BalancesService, getTransactions: GetTransactions, private val searchTokensCase: SearchTokensCase, private val getDeviceIdCase: GetDeviceIdCase, @@ -79,7 +80,13 @@ class AssetsRepository @Inject constructor( private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO), ) : GetAsset { - private val visibleByDefault = listOf(Chain.Ethereum, Chain.Bitcoin, Chain.SmartChain, Chain.Solana) + private val visibleByDefault = listOf( + Chain.Ethereum, + Chain.Bitcoin, + Chain.SmartChain, + Chain.Solana, + Chain.Tron, + ) init { scope.launch(Dispatchers.IO) { @@ -454,14 +461,14 @@ class AssetsRepository @Inject constructor( val getNative = async { val prevBalance = balancesDao.getByAccount(walletId, account.address, account.chain.string) - val nativeBalance = balancesRemoteSource.getNativeBalances(account) + val nativeBalance = balancesService.getNativeBalances(account) val dbNativeBalance = DbBalance.mergeNative( prevBalance, nativeBalance?.toRecord(walletId, account.address, updatedAt), ) dbNativeBalance?.let { runCatching { balancesDao.insert(it) } } - val delegationBalances = balancesRemoteSource.getDelegationBalances(account) + val delegationBalances = balancesService.getDelegationBalances(account) val dbFullBalance = DbBalance.mergeDelegation(dbNativeBalance, delegationBalances ?.toRecord(walletId, account.address, updatedAt)) dbFullBalance?.let { runCatching { balancesDao.insert(it) } } @@ -469,7 +476,7 @@ class AssetsRepository @Inject constructor( } val getTokens = async { - val balances = balancesRemoteSource.getTokensBalances(account, tokens) + val balances = balancesService.getTokensBalances(account, tokens) runCatching { balancesDao.insert( balances.map { diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/BalancesRemoteSource.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/BalancesRemoteSource.kt deleted file mode 100644 index 036a03cc5..000000000 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/assets/BalancesRemoteSource.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.gemwallet.android.data.repositoreis.assets - -import com.gemwallet.android.blockchain.clients.BalanceClient -import com.gemwallet.android.blockchain.clients.getClient -import com.gemwallet.android.ext.type -import com.gemwallet.android.model.AssetBalance -import com.wallet.core.primitives.Account -import com.wallet.core.primitives.Asset -import com.wallet.core.primitives.AssetSubtype -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class BalancesRemoteSource @Inject constructor( - private val balanceClients: List, -) { - - suspend fun getNativeBalances(account: Account): AssetBalance? { - val client = balanceClients.getClient(account.chain) ?: return null - return try { - client.getNativeBalance(account.chain, account.address) - } catch (_: Throwable) { - null - } - } - - suspend fun getDelegationBalances(account: Account): AssetBalance? { - val client = balanceClients.getClient(account.chain) ?: return null - return try { - client.getDelegationBalances(account.chain, account.address) - } catch (_: Throwable) { - null - } - } - - suspend fun getTokensBalances(account: Account, tokens: List): List { - val client = balanceClients.getClient(account.chain) ?: return emptyList() - - val tokens = tokens.filter { it.id.type() == AssetSubtype.TOKEN && account.chain == it.id.chain } - .ifEmpty { return emptyList() } - val tokensBalances = try { - client.getTokenBalances(account.chain, account.address, tokens) - } catch (_: Throwable) { - emptyList() - } - return tokensBalances - } -} \ No newline at end of file diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/banners/BannersRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/banners/BannersRepository.kt index d6cde5780..d97ecf200 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/banners/BannersRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/banners/BannersRepository.kt @@ -84,6 +84,7 @@ class BannersRepository( BannerEvent.EnableNotifications, BannerEvent.AccountBlockedMultiSignature -> BannerState.Active BannerEvent.ActivateAsset -> BannerState.AlwaysActive + BannerEvent.SuspiciousAsset -> throw IllegalArgumentException() // TODO: HyperCore }, event = event, ) diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/BridgesRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/BridgesRepository.kt index 5b3033666..332a08e46 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/BridgesRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/BridgesRepository.kt @@ -283,10 +283,10 @@ class BridgesRepository( chains = chain.value.map { "${it.namespace}:${it.reference}" }, methods = chain.value.map { it.methods }.toSet().flatten().toList(), events = if (chain.key == Chain.Solana.string) emptyList() else listOf( - WalletConnectionEvents.connect.string, - WalletConnectionEvents.disconnect.string, - WalletConnectionEvents.chain_changed.string, - WalletConnectionEvents.accounts_changed.string + WalletConnectionEvents.Connect.string, + WalletConnectionEvents.Disconnect.string, + WalletConnectionEvents.ChainChanged.string, + WalletConnectionEvents.AccountsChanged.string ), accounts = chain.value.map { "${it.namespace}:${it.reference}:${it.address}" }, ) diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/Namespace.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/Namespace.kt index d70996719..4c4c3e111 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/Namespace.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/bridge/Namespace.kt @@ -1,5 +1,6 @@ package com.gemwallet.android.data.repositoreis.bridge +import com.gemwallet.android.ext.toChain import com.gemwallet.android.ext.toChainType import com.wallet.core.primitives.Chain import com.wallet.core.primitives.ChainType @@ -10,23 +11,23 @@ enum class ChainNamespace(val string: String, val methods: List= 2) { - WalletConnectNamespace().getChain(chainId[0], chainId[1])?.let { namespace -> - Chain.entries.firstOrNull { it.string == namespace } - } + WalletConnectNamespace().getChain(chainId[0], chainId[1])?.toChain() } else { null } diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/config/SecurityGemPreferences.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/config/SecurityGemPreferences.kt new file mode 100644 index 000000000..053075749 --- /dev/null +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/config/SecurityGemPreferences.kt @@ -0,0 +1,42 @@ +package com.gemwallet.android.data.repositoreis.config + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey +import uniffi.gemstone.GemPreferences + +class SecurityGemPreferences( + private val context: Context, +) : GemPreferences { + + override fun get(key: String): String? { + return getStore().getString(key, null) + } + + override fun set(key: String, value: String) { + getStore().edit(commit = true) { + putString(key, value) + } + } + + override fun remove(key: String) { + getStore().edit(commit = true) { + remove(key) + } + } + + private fun getStore(): SharedPreferences { + val masterKey = MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + return EncryptedSharedPreferences.create( + context, + "pwd", + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, + ) + } +} \ No newline at end of file diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/config/SharedGemPreferences.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/config/SharedGemPreferences.kt new file mode 100644 index 000000000..68fdcab60 --- /dev/null +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/config/SharedGemPreferences.kt @@ -0,0 +1,22 @@ +package com.gemwallet.android.data.repositoreis.config + +import android.content.SharedPreferences +import uniffi.gemstone.GemPreferences +import androidx.core.content.edit + +class SharedGemPreferences( + private val sharedPreferences: SharedPreferences +) : GemPreferences { + + override fun get(key: String): String? { + return sharedPreferences.getString(key, null) + } + + override fun set(key: String, value: String) { + sharedPreferences.edit(commit = true) { putString(key, value) } + } + + override fun remove(key: String) { + sharedPreferences.edit(commit = true) { remove(key) } + } +} \ No newline at end of file diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/AssetsModule.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/AssetsModule.kt index 325206258..877c3e93c 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/AssetsModule.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/AssetsModule.kt @@ -1,26 +1,12 @@ package com.gemwallet.android.data.repositoreis.di import com.gemwallet.android.blockchain.RpcClientAdapter -import com.gemwallet.android.blockchain.clients.algorand.AlgorandBalanceClient -import com.gemwallet.android.blockchain.clients.aptos.AptosBalanceClient -import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinBalanceClient -import com.gemwallet.android.blockchain.clients.cardano.CardanoBalanceClient -import com.gemwallet.android.blockchain.clients.cosmos.CosmosBalanceClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmBalanceClient -import com.gemwallet.android.blockchain.clients.ethereum.SmartchainStakeClient -import com.gemwallet.android.blockchain.clients.near.NearBalanceClient -import com.gemwallet.android.blockchain.clients.polkadot.PolkadotBalancesClient -import com.gemwallet.android.blockchain.clients.solana.SolanaBalanceClient -import com.gemwallet.android.blockchain.clients.stellar.StellarBalanceClient -import com.gemwallet.android.blockchain.clients.sui.SuiBalanceClient -import com.gemwallet.android.blockchain.clients.ton.TonBalanceClient -import com.gemwallet.android.blockchain.clients.tron.TronBalanceClient -import com.gemwallet.android.blockchain.clients.xrp.XrpBalanceClient +//import com.gemwallet.android.blockchain.clients.ethereum.EvmBalanceClient import com.gemwallet.android.cases.device.GetDeviceIdCase import com.gemwallet.android.cases.tokens.SearchTokensCase import com.gemwallet.android.cases.transactions.GetTransactions import com.gemwallet.android.data.repositoreis.assets.AssetsRepository -import com.gemwallet.android.data.repositoreis.assets.BalancesRemoteSource +import com.gemwallet.android.blockchain.services.BalancesService import com.gemwallet.android.data.repositoreis.assets.PriceWebSocketClient import com.gemwallet.android.data.repositoreis.session.SessionRepository import com.gemwallet.android.data.service.store.database.AssetsDao @@ -37,6 +23,9 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.AlienProvider +import uniffi.gemstone.GemGateway +import uniffi.gemstone.GemPreferences import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -51,7 +40,7 @@ object AssetsModule { balancesDao: BalancesDao, pricesDao: PricesDao, sessionRepository: SessionRepository, - balancesRemoteSource: BalancesRemoteSource, + balancesService: BalancesService, getTransactions: GetTransactions, searchTokensCase: SearchTokensCase, getDeviceIdCase: GetDeviceIdCase, @@ -64,7 +53,7 @@ object AssetsModule { pricesDao = pricesDao, sessionRepository = sessionRepository, getTransactions = getTransactions, - balancesRemoteSource = balancesRemoteSource, + balancesService = balancesService, searchTokensCase = searchTokensCase, getDeviceIdCase = getDeviceIdCase, priceClient = priceClient @@ -73,26 +62,9 @@ object AssetsModule { @Provides @Singleton fun provideBalanceRemoteSource( - rpcClients: RpcClientAdapter, - ): BalancesRemoteSource = BalancesRemoteSource( - Chain.available().map { - when (it.toChainType()) { - ChainType.Bitcoin -> BitcoinBalanceClient(it, rpcClients.getClient(it)) - ChainType.Ethereum -> EvmBalanceClient(it, rpcClients.getClient(it), rpcClients.getClient(it), SmartchainStakeClient(it, rpcClients.getClient(it))) - ChainType.Solana -> SolanaBalanceClient(it, rpcClients.getClient(Chain.Solana), rpcClients.getClient(Chain.Solana), rpcClients.getClient(Chain.Solana)) - ChainType.Cosmos -> CosmosBalanceClient(it, rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Ton -> TonBalanceClient(it, rpcClients.getClient(Chain.Ton)) - ChainType.Tron -> TronBalanceClient(it, rpcClients.getClient(Chain.Tron), rpcClients.getClient(Chain.Tron), rpcClients.getClient(Chain.Tron)) - ChainType.Aptos -> AptosBalanceClient(it, rpcClients.getClient(it)) - ChainType.Sui -> SuiBalanceClient(it, rpcClients.getClient(it)) - ChainType.Xrp -> XrpBalanceClient(it, rpcClients.getClient(it)) - ChainType.Near -> NearBalanceClient(it, rpcClients.getClient(it)) - ChainType.Algorand -> AlgorandBalanceClient(it, rpcClients.getClient(it)) - ChainType.Stellar -> StellarBalanceClient(it, rpcClients.getClient(it)) - ChainType.Polkadot -> PolkadotBalancesClient(it, rpcClients.getClient(it)) - ChainType.Cardano -> CardanoBalanceClient(it, rpcClients.getClient(it)) - } - } + gateway: GemGateway, + ): BalancesService = BalancesService( + gateway = gateway, ) @Provides diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/StakeModule.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/StakeModule.kt index a728c224a..33f61441e 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/StakeModule.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/StakeModule.kt @@ -1,23 +1,15 @@ package com.gemwallet.android.data.repositoreis.di -import com.gemwallet.android.blockchain.RpcClientAdapter -import com.gemwallet.android.blockchain.clients.cosmos.CosmosStakeClient -import com.gemwallet.android.blockchain.clients.ethereum.SmartchainStakeClient -import com.gemwallet.android.blockchain.clients.solana.SolanaStakeClient -import com.gemwallet.android.blockchain.clients.sui.SuiStakeClient -import com.gemwallet.android.blockchain.clients.tron.TronStakeClient +import com.gemwallet.android.blockchain.services.StakeService import com.gemwallet.android.data.repositoreis.stake.StakeRepository import com.gemwallet.android.data.service.store.database.StakeDao import com.gemwallet.android.data.services.gemapi.GemApiClient import com.gemwallet.android.data.services.gemapi.GemApiStaticClient -import com.gemwallet.android.ext.available -import com.gemwallet.android.ext.toChainType -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.ChainType import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.GemGateway import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -27,40 +19,14 @@ object StakeModule { @Provides fun provideStakeRepository( stakeDao: StakeDao, - rpcClients: RpcClientAdapter, + gateway: GemGateway, gemApiStaticClient: GemApiStaticClient, gemApiClient: GemApiClient, ): StakeRepository = StakeRepository( stakeDao = stakeDao, gemApiStaticClient = gemApiStaticClient, gemApiClient = gemApiClient, - stakeClients = Chain.available().mapNotNull { - when (it.toChainType()) { - ChainType.Ethereum -> when (it) { - Chain.SmartChain -> SmartchainStakeClient(it, rpcClients.getClient(it)) - else -> null - } - ChainType.Solana -> SolanaStakeClient(it, rpcClients.getClient(it)) - ChainType.Cosmos -> { - when (it) { - Chain.Noble, Chain.Thorchain -> null - else -> CosmosStakeClient(it, rpcClients.getClient(it)) - } - } - ChainType.Sui -> SuiStakeClient(it, rpcClients.getClient(it)) - ChainType.Tron -> TronStakeClient(it, rpcClients.getClient(it), rpcClients.getClient(it)) - ChainType.Bitcoin, - ChainType.Ton, - ChainType.Tron, - ChainType.Aptos, - ChainType.Xrp, - ChainType.Algorand, - ChainType.Stellar, - ChainType.Polkadot, - ChainType.Cardano, - ChainType.Near -> null - } - } + stakeService = StakeService(gateway), ) } diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/SwapModule.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/SwapModule.kt index 5479e4ee9..6fa3879be 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/SwapModule.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/SwapModule.kt @@ -1,9 +1,11 @@ package com.gemwallet.android.data.repositoreis.di -import com.gemwallet.android.blockchain.clients.SignClientProxy +import com.gemwallet.android.blockchain.services.SignClientProxy import com.gemwallet.android.blockchain.operators.LoadPrivateKeyOperator import com.gemwallet.android.blockchain.operators.PasswordStore import com.gemwallet.android.cases.nodes.GetCurrentNodeCase +import com.gemwallet.android.cases.nodes.GetNodesCase +import com.gemwallet.android.cases.nodes.SetCurrentNodeCase import com.gemwallet.android.cases.swap.GetSwapQuotes import com.gemwallet.android.cases.swap.GetSwapSupported import com.gemwallet.android.data.repositoreis.swap.NativeProvider @@ -12,6 +14,7 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.AlienProvider import uniffi.gemstone.GemSwapper import javax.inject.Singleton @@ -21,9 +24,19 @@ object SwapModule { @Singleton @Provides - fun provideGemSwapper( + fun provideAlienProvider( + getNodesCase: GetNodesCase, getCurrentNodeCase: GetCurrentNodeCase, - ) = GemSwapper(NativeProvider(getCurrentNodeCase)) + setCurrentNodeCase: SetCurrentNodeCase, + ): AlienProvider { + return NativeProvider(getNodesCase, getCurrentNodeCase, setCurrentNodeCase) + } + + @Singleton + @Provides + fun provideGemSwapper( + alienProvider: AlienProvider, + ) = GemSwapper(alienProvider) @Singleton @Provides diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TokensModule.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TokensModule.kt index 31391fd49..c67547ec5 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TokensModule.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TokensModule.kt @@ -1,25 +1,16 @@ package com.gemwallet.android.data.repositoreis.di -import com.gemwallet.android.blockchain.RpcClientAdapter -import com.gemwallet.android.blockchain.clients.aptos.AptosGetTokenClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmGetTokenClient -import com.gemwallet.android.blockchain.clients.solana.SolanaTokenClient -import com.gemwallet.android.blockchain.clients.sui.SuiGetTokenClient -import com.gemwallet.android.blockchain.clients.ton.TonGetTokenClient -import com.gemwallet.android.blockchain.clients.tron.TronGetTokenClient +import com.gemwallet.android.blockchain.services.TokenService import com.gemwallet.android.cases.tokens.SearchTokensCase import com.gemwallet.android.data.repositoreis.tokens.TokensRepository import com.gemwallet.android.data.service.store.database.AssetsDao import com.gemwallet.android.data.service.store.database.AssetsPriorityDao import com.gemwallet.android.data.services.gemapi.GemApiClient -import com.gemwallet.android.ext.available -import com.gemwallet.android.ext.toChainType -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.ChainType import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.GemGateway import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -30,30 +21,16 @@ object TokensModule { fun provideTokensRepository( assetsDao: AssetsDao, assetsPriorityDao: AssetsPriorityDao, + gateway: GemGateway, gemApiClient: GemApiClient, - rpcClients: RpcClientAdapter, ): TokensRepository = TokensRepository( assetsDao = assetsDao, assetsPriorityDao = assetsPriorityDao, gemApiClient = gemApiClient, - getTokenClients = Chain.available().mapNotNull { chain -> - when (chain.toChainType()) { - ChainType.Ethereum -> EvmGetTokenClient(chain, rpcClients.getClient(chain)) - ChainType.Solana -> SolanaTokenClient(chain, rpcClients.getClient(chain)) - ChainType.Ton -> TonGetTokenClient(chain, rpcClients.getClient(chain)) - ChainType.Tron -> TronGetTokenClient(chain, rpcClients.getClient(chain)) - ChainType.Sui -> SuiGetTokenClient(chain, rpcClients.getClient(chain)) - ChainType.Aptos -> AptosGetTokenClient(chain, rpcClients.getClient(chain)) - ChainType.Bitcoin, - ChainType.Cosmos, - ChainType.Xrp, - ChainType.Algorand, - ChainType.Stellar, - ChainType.Polkadot, - ChainType.Cardano, - ChainType.Near -> null - } - } + tokenService = TokenService( + gateway = gateway, + ), + ) @Provides diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TransactionsModule.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TransactionsModule.kt index 190ad9f0b..c6fabc3fd 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TransactionsModule.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/di/TransactionsModule.kt @@ -1,20 +1,7 @@ package com.gemwallet.android.data.repositoreis.di import com.gemwallet.android.blockchain.RpcClientAdapter -import com.gemwallet.android.blockchain.clients.algorand.AlgorandTransactionStatusClient -import com.gemwallet.android.blockchain.clients.aptos.AptosTransactionStatusClient -import com.gemwallet.android.blockchain.clients.bitcoin.BitcoinTransactionStatusClient -import com.gemwallet.android.blockchain.clients.cardano.CardanoTransactionStatusClient -import com.gemwallet.android.blockchain.clients.cosmos.CosmosTransactionStatusClient -import com.gemwallet.android.blockchain.clients.ethereum.EvmTransactionStatusClient -import com.gemwallet.android.blockchain.clients.near.NearTransactionStatusClient -import com.gemwallet.android.blockchain.clients.polkadot.PolkadotTransactionStatusClient -import com.gemwallet.android.blockchain.clients.solana.SolanaTransactionStatusClient -import com.gemwallet.android.blockchain.clients.stellar.StellarTransactionStatusClient -import com.gemwallet.android.blockchain.clients.sui.SuiTransactionStatusClient -import com.gemwallet.android.blockchain.clients.ton.TonTransactionStatusClient -import com.gemwallet.android.blockchain.clients.tron.TronTransactionStatusClient -import com.gemwallet.android.blockchain.clients.xrp.XrpTransactionStatusClient +import com.gemwallet.android.blockchain.services.TransactionStatusService import com.gemwallet.android.cases.device.GetDeviceIdCase import com.gemwallet.android.cases.transactions.ClearPendingTransactions import com.gemwallet.android.cases.transactions.CreateTransaction @@ -30,14 +17,11 @@ import com.gemwallet.android.data.repositoreis.transactions.TransactionsReposito import com.gemwallet.android.data.service.store.database.AssetsDao import com.gemwallet.android.data.service.store.database.TransactionsDao import com.gemwallet.android.data.services.gemapi.GemApiClient -import com.gemwallet.android.ext.available -import com.gemwallet.android.ext.toChainType -import com.wallet.core.primitives.Chain -import com.wallet.core.primitives.ChainType import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import uniffi.gemstone.GemGateway import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -49,28 +33,14 @@ object TransactionsModule { fun provideTransactionsRepository( transactionsDao: TransactionsDao, assetsDao: AssetsDao, + gateway: GemGateway, rpcClients: RpcClientAdapter, ): TransactionsRepository = TransactionsRepository( transactionsDao = transactionsDao, assetsDao = assetsDao, - stateClients = Chain.available().map { - when (it.toChainType()) { - ChainType.Bitcoin -> BitcoinTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Ethereum -> EvmTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Solana -> SolanaTransactionStatusClient(it, rpcClients.getClient(Chain.Solana)) - ChainType.Cosmos -> CosmosTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Ton -> TonTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Tron -> TronTransactionStatusClient(it, rpcClients.getClient(Chain.Tron)) - ChainType.Aptos -> AptosTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Sui -> SuiTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Xrp -> XrpTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Near -> NearTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Algorand -> AlgorandTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Stellar -> StellarTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Polkadot -> PolkadotTransactionStatusClient(it, rpcClients.getClient(it)) - ChainType.Cardano -> CardanoTransactionStatusClient(it, rpcClients.getClient(it)) - } - }, + transactionStatusService = TransactionStatusService( + gateway = gateway, + ), ) @Singleton diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/stake/StakeRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/stake/StakeRepository.kt index 193a7b971..70a481575 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/stake/StakeRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/stake/StakeRepository.kt @@ -1,6 +1,6 @@ package com.gemwallet.android.data.repositoreis.stake -import com.gemwallet.android.blockchain.clients.StakeClient +import com.gemwallet.android.blockchain.services.StakeService import com.gemwallet.android.data.service.store.database.StakeDao import com.gemwallet.android.data.service.store.database.entities.toModel import com.gemwallet.android.data.service.store.database.entities.toRecord @@ -15,12 +15,8 @@ import com.wallet.core.primitives.DelegationBase import com.wallet.core.primitives.DelegationValidator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withContext import uniffi.gemstone.Config import java.math.BigInteger @@ -28,11 +24,12 @@ import java.math.BigInteger class StakeRepository( private val gemApiStaticClient: GemApiStaticClient, private val gemApiClient: GemApiClient, - private val stakeClients: List, + private val stakeService: StakeService, private val stakeDao: StakeDao, ) { private val recommendedValidators = Config().getValidators() + suspend fun sync(chain: Chain, address: String) = withContext(Dispatchers.IO) { val apr = try { gemApiClient.getAsset(chain.string, Currency.USD.string).properties.stakingApr ?: return@withContext @@ -40,12 +37,12 @@ class StakeRepository( return@withContext } syncValidators(chain, apr) - syncDelegations(chain, address, apr) + syncDelegations(chain, address) } - private suspend fun syncDelegations(chain: Chain, address: String, apr: Double) = withContext(Dispatchers.IO) { + private suspend fun syncDelegations(chain: Chain, address: String) = withContext(Dispatchers.IO) { val delegations = try { - stakeClients.firstOrNull { it.supported(chain) }?.getStakeDelegations(chain, address, apr) ?: return@withContext + stakeService.getStakeDelegations(chain, address) } catch (_: Throwable) { return@withContext } @@ -61,18 +58,7 @@ class StakeRepository( } catch (_: Throwable) { emptyMap() } - val validators = stakeClients.filter { it.supported(chain) } - .asFlow() - .mapNotNull { - try { - it.getValidators(chain, apr) - } catch (_: Throwable) { - null - } - } - .flowOn(Dispatchers.IO) - .toList() - .flatten() + val validators = stakeService.getValidators(chain, apr) .map { if (it.name.isEmpty()) { it.copy(name = validatorsInfo[it.id]?.name ?: "") diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/NativeProvider.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/NativeProvider.kt index c7b6bbe7d..1fcda227e 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/NativeProvider.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/NativeProvider.kt @@ -1,7 +1,10 @@ package com.gemwallet.android.data.repositoreis.swap import com.gemwallet.android.cases.nodes.GetCurrentNodeCase -import com.wallet.core.primitives.Chain +import com.gemwallet.android.cases.nodes.GetNodesCase +import com.gemwallet.android.cases.nodes.SetCurrentNodeCase +import com.gemwallet.android.data.services.gemapi.http.getNodeUrl +import com.gemwallet.android.ext.toChain import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -13,14 +16,15 @@ import uniffi.gemstone.AlienProvider import uniffi.gemstone.AlienTarget class NativeProvider( + private val getNodesCase: GetNodesCase, private val getCurrentNodeCase: GetCurrentNodeCase, + private val setCurrentNodeCase: SetCurrentNodeCase, private val httpClient: OkHttpClient = OkHttpClient(), ): AlienProvider { override fun getEndpoint(chain: uniffi.gemstone.Chain): String { - return Chain.entries.firstOrNull { it.string == chain }?.let { - getCurrentNodeCase.getCurrentNode(it)?.url - } ?: throw IllegalArgumentException("Can't found node url for chain: $chain") + return chain.toChain()?.getNodeUrl(getNodesCase, getCurrentNodeCase, setCurrentNodeCase) + ?: throw IllegalArgumentException("Can't found node url for chain: $chain") } override suspend fun batchRequest(targets: List): List = withContext(Dispatchers.IO) { diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/SwapRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/SwapRepository.kt index e418a8367..811a058e1 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/SwapRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/swap/SwapRepository.kt @@ -1,6 +1,6 @@ package com.gemwallet.android.data.repositoreis.swap -import com.gemwallet.android.blockchain.clients.SignClientProxy +import com.gemwallet.android.blockchain.services.SignClientProxy import com.gemwallet.android.blockchain.operators.LoadPrivateKeyOperator import com.gemwallet.android.blockchain.operators.PasswordStore import com.gemwallet.android.cases.swap.GetSwapQuotes diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/tokens/TokensRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/tokens/TokensRepository.kt index 79ec3a285..eea9e4cd4 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/tokens/TokensRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/tokens/TokensRepository.kt @@ -1,6 +1,6 @@ package com.gemwallet.android.data.repositoreis.tokens -import com.gemwallet.android.blockchain.clients.GetTokenClient +import com.gemwallet.android.blockchain.services.TokenService import com.gemwallet.android.cases.tokens.SearchTokensCase import com.gemwallet.android.data.service.store.database.AssetsDao import com.gemwallet.android.data.service.store.database.AssetsPriorityDao @@ -12,15 +12,13 @@ import com.wallet.core.primitives.AssetId import com.wallet.core.primitives.AssetProperties import com.wallet.core.primitives.AssetScore import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll import kotlinx.coroutines.withContext class TokensRepository ( private val assetsDao: AssetsDao, private val assetsPriorityDao: AssetsPriorityDao, private val gemApiClient: GemApiClient, - private val getTokenClients: List, + private val tokenService: TokenService, ) : SearchTokensCase { override suspend fun search(query: String): Boolean = withContext(Dispatchers.IO) { @@ -33,28 +31,7 @@ class TokensRepository ( return@withContext false } val assets = if (tokens.isEmpty()) { - val assets = getTokenClients.map { - async { - try { - if (it.isTokenQuery(query)) { - it.getTokenData(query) - } else { - null - } - } catch (_: Throwable) { - null - } - } - } - .awaitAll() - .mapNotNull { it } - .map { AssetBasic(asset = it, score = AssetScore(0), properties = AssetProperties( - isEnabled = false, - isBuyable = false, - isSellable = false, - isSwapable = false, - isStakeable = false - )) } + val assets = tokenService.search(query) runCatching { assetsDao.insert(assets.map { it.toRecord() }) } assets } else { @@ -67,9 +44,7 @@ class TokensRepository ( override suspend fun search(assetId: AssetId): Boolean { val tokenId = assetId.tokenId ?: return false - val asset = getTokenClients - .firstOrNull { it.supported(assetId.chain) && it.isTokenQuery(tokenId) } - ?.getTokenData(tokenId) + val asset = tokenService.getTokenData(assetId) if (asset == null) { return search(tokenId) } @@ -80,7 +55,7 @@ class TokensRepository ( isSwapable = false, isStakeable = false )) - .toRecord() + .toRecord() runCatching { assetsDao.insert(record) } return true } diff --git a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/transactions/TransactionsRepository.kt b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/transactions/TransactionsRepository.kt index c63e8333a..4b11ba3cc 100644 --- a/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/transactions/TransactionsRepository.kt +++ b/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositoreis/transactions/TransactionsRepository.kt @@ -2,9 +2,9 @@ package com.gemwallet.android.data.repositoreis.transactions import android.text.format.DateUtils import android.util.Log -import com.gemwallet.android.blockchain.clients.ServiceUnavailable -import com.gemwallet.android.blockchain.clients.TransactionStateRequest -import com.gemwallet.android.blockchain.clients.TransactionStatusClient +import com.gemwallet.android.blockchain.model.ServiceUnavailable +import com.gemwallet.android.blockchain.model.TransactionStateRequest +import com.gemwallet.android.blockchain.services.TransactionStatusService import com.gemwallet.android.cases.transactions.ClearPendingTransactions import com.gemwallet.android.cases.transactions.CreateTransaction import com.gemwallet.android.cases.transactions.GetTransaction @@ -51,9 +51,9 @@ import java.util.concurrent.ConcurrentHashMap @OptIn(ExperimentalCoroutinesApi::class) class TransactionsRepository( private val transactionsDao: TransactionsDao, - assetsDao: AssetsDao, - private val stateClients: List, + private val transactionStatusService: TransactionStatusService, private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO), + assetsDao: AssetsDao, ) : GetTransactions, GetTransaction, @@ -246,16 +246,14 @@ class TransactionsRepository( private suspend fun checkTx(tx: DbTransactionExtended): DbTransactionExtended? { val assetId = tx.assetId.toAssetId() ?: return null - val stateClient = stateClients.firstOrNull { it.supported(assetId.chain) } ?: return null + val request = TransactionStateRequest( + chain = assetId.chain, + sender = tx.owner, + hash = tx.hash, + block = tx.blockNumber, + ) val state = try { - stateClient.getStatus( - TransactionStateRequest( - chain = assetId.chain, - sender = tx.owner, - hash = tx.hash, - block = tx.blockNumber, - ) - ) + transactionStatusService.getStatus(request) ?: TransactionChanges(tx.state) } catch (_: ServiceUnavailable) { return tx.copy(updatedAt = System.currentTimeMillis()) } catch (_: Throwable) { diff --git a/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/di/ClientsModule.kt b/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/di/ClientsModule.kt index 97a8e9cc2..194b2de7e 100644 --- a/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/di/ClientsModule.kt +++ b/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/di/ClientsModule.kt @@ -3,20 +3,7 @@ package com.gemwallet.android.data.services.gemapi.di import android.content.Context import com.gemwallet.android.blockchain.Mime import com.gemwallet.android.blockchain.RpcClientAdapter -import com.gemwallet.android.blockchain.clients.algorand.services.AlgorandService -import com.gemwallet.android.blockchain.clients.aptos.services.AptosServices -import com.gemwallet.android.blockchain.clients.bitcoin.services.BitcoinRpcClient -import com.gemwallet.android.blockchain.clients.cardano.services.CardanoServices -import com.gemwallet.android.blockchain.clients.cosmos.services.CosmosRpcClient -import com.gemwallet.android.blockchain.clients.ethereum.services.EvmRpcClient -import com.gemwallet.android.blockchain.clients.near.NearRpcClient -import com.gemwallet.android.blockchain.clients.polkadot.services.PolkadotServices -import com.gemwallet.android.blockchain.clients.solana.services.SolanaRpcClient -import com.gemwallet.android.blockchain.clients.stellar.services.StellarService -import com.gemwallet.android.blockchain.clients.sui.SuiRpcClient -import com.gemwallet.android.blockchain.clients.ton.TonRpcClient import com.gemwallet.android.blockchain.clients.tron.TronRpcClient -import com.gemwallet.android.blockchain.clients.xrp.XrpRpcClient import com.gemwallet.android.cases.nodes.GetCurrentNodeCase import com.gemwallet.android.cases.nodes.GetNodesCase import com.gemwallet.android.cases.nodes.SetCurrentNodeCase @@ -128,39 +115,56 @@ object ClientsModule { @NodeHttpClient httpClient: OkHttpClient, ): RpcClientAdapter { val gson = Gson() - val converter = jsonEncoder.asConverterFactory(Mime.Json.value) - val ethConverter = GsonConverterFactory.create( - gson.newBuilder() - .registerTypeAdapter(EvmRpcClient.EvmNumber::class.java, EvmRpcClient.BalanceDeserializer()) - .registerTypeAdapter(EvmRpcClient.TokenBalance::class.java, EvmRpcClient.TokenBalanceDeserializer()) - .create() - ) - val tonConverter = GsonConverterFactory.create( - gson.newBuilder() - .registerTypeAdapter(TonRpcClient.JetonAddress::class.java, TonRpcClient.JetonAddressSerializer()) - .create() - ) +// val converter = jsonEncoder.asConverterFactory(Mime.Json.value) +// val ethConverter = GsonConverterFactory.create( +// gson.newBuilder() +// .registerTypeAdapter(EvmRpcClient.EvmNumber::class.java, EvmRpcClient.BalanceDeserializer()) +// .registerTypeAdapter(EvmRpcClient.TokenBalance::class.java, EvmRpcClient.TokenBalanceDeserializer()) +// .create() +// ) +// val tonConverter = GsonConverterFactory.create( +// gson.newBuilder() +// .registerTypeAdapter(TonRpcClient.JetonAddress::class.java, TonRpcClient.JetonAddressSerializer()) +// .create() +// ) val gsonConverter = GsonConverterFactory.create(gson) val adapter = RpcClientAdapter() - Chain.available().map { - val url = "https://${it.string}" - val rpc: Any = when (it.toChainType()) { - ChainType.Bitcoin -> buildClient(url, BitcoinRpcClient::class.java, converter, httpClient) - ChainType.Ethereum -> buildClient(url, EvmRpcClient::class.java, ethConverter, httpClient) - ChainType.Solana -> buildClient(url, SolanaRpcClient::class.java, gsonConverter, httpClient) - ChainType.Cosmos -> buildClient(url, CosmosRpcClient::class.java, converter, httpClient) - ChainType.Ton -> buildClient(url, TonRpcClient::class.java, tonConverter, httpClient) + Chain.available().forEach { chain -> + val url = "https://${chain.string}" + when (chain.toChainType()) { ChainType.Tron -> buildClient(url, TronRpcClient::class.java, gsonConverter, httpClient) - ChainType.Aptos -> buildClient(url, AptosServices::class.java, converter, httpClient) - ChainType.Sui -> buildClient(url, SuiRpcClient::class.java, gsonConverter, httpClient) - ChainType.Xrp -> buildClient(url, XrpRpcClient::class.java, gsonConverter, httpClient) - ChainType.Near -> buildClient(url, NearRpcClient::class.java, gsonConverter, httpClient) - ChainType.Algorand -> buildClient(url, AlgorandService::class.java, converter, httpClient) - ChainType.Stellar -> buildClient(url, StellarService::class.java, converter, httpClient) - ChainType.Polkadot -> buildClient(url, PolkadotServices::class.java, converter, httpClient) - ChainType.Cardano -> buildClient(url, CardanoServices::class.java, converter, httpClient) +// ChainType.Bitcoin -> buildClient(url, BitcoinRpcClient::class.java, converter, httpClient) +// ChainType.Ethereum -> buildClient(url, EvmRpcClient::class.java, ethConverter, httpClient) +// ChainType.Solana -> return@forEach +// ChainType.Cosmos -> buildClient(url, CosmosRpcClient::class.java, converter, httpClient) +// ChainType.Ton -> buildClient(url, TonRpcClient::class.java, tonConverter, httpClient) + +// ChainType.Aptos -> buildClient(url, AptosServices::class.java, converter, httpClient) +// ChainType.Sui -> buildClient(url, SuiRpcClient::class.java, gsonConverter, httpClient) +// ChainType.Xrp -> buildClient(url, XrpRpcClient::class.java, gsonConverter, httpClient) +// ChainType.Near -> buildClient(url, NearRpcClient::class.java, gsonConverter, httpClient) +// ChainType.Algorand -> buildClient(url, AlgorandService::class.java, converter, httpClient) +// ChainType.Stellar -> buildClient(url, StellarService::class.java, converter, httpClient) +// ChainType.Polkadot -> buildClient(url, PolkadotServices::class.java, converter, httpClient) +// ChainType.Cardano -> buildClient(url, CardanoServices::class.java, converter, httpClient) +// ChainType.HyperCore -> null + ChainType.Ethereum, + ChainType.Bitcoin, + ChainType.Solana, + ChainType.Cosmos, + ChainType.Ton, + ChainType.Aptos, + ChainType.Sui, + ChainType.Xrp, + ChainType.Near, + ChainType.Stellar, + ChainType.Algorand, + ChainType.Polkadot, + ChainType.Cardano, + ChainType.HyperCore -> null + }?.let { rpc -> + adapter.add(chain, rpc) } - adapter.add(it, rpc) } return adapter } diff --git a/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/GetNodeUrl.kt b/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/GetNodeUrl.kt new file mode 100644 index 000000000..37c741fb9 --- /dev/null +++ b/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/GetNodeUrl.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.data.services.gemapi.http + +import com.gemwallet.android.cases.nodes.GetCurrentNodeCase +import com.gemwallet.android.cases.nodes.GetNodesCase +import com.gemwallet.android.cases.nodes.SetCurrentNodeCase +import com.wallet.core.primitives.Chain +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.runBlocking + +fun Chain.getNodeUrl( + getNodesCase: GetNodesCase, + getCurrentNodeCase: GetCurrentNodeCase, + setCurrentNodeCase: SetCurrentNodeCase +): String? { + val currentNode = getCurrentNodeCase.getCurrentNode(this) + val url = if (currentNode == null) { + val node = runBlocking { getNodesCase.getNodes(this@getNodeUrl).firstOrNull()?.firstOrNull() } + if (node != null) { + setCurrentNodeCase.setCurrentNode(this, node) + } + node + } else { + currentNode + }?.url + return url +} \ No newline at end of file diff --git a/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/NodeSelectorInterceptor.kt b/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/NodeSelectorInterceptor.kt index 00363ffd1..2c653595c 100644 --- a/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/NodeSelectorInterceptor.kt +++ b/data/services/remote-gem/src/main/kotlin/com/gemwallet/android/data/services/gemapi/http/NodeSelectorInterceptor.kt @@ -4,6 +4,7 @@ import android.util.Log import com.gemwallet.android.cases.nodes.GetCurrentNodeCase import com.gemwallet.android.cases.nodes.GetNodesCase import com.gemwallet.android.cases.nodes.SetCurrentNodeCase +import com.gemwallet.android.ext.toChain import com.wallet.core.primitives.Chain import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking @@ -21,18 +22,8 @@ class NodeSelectorInterceptor( override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() - val blockchain = Chain.entries.firstOrNull { it.string == originalRequest.url.host } - ?: return chain.proceed(originalRequest) - val currentNode = getCurrentNodeCase.getCurrentNode(blockchain) - val url = if (currentNode == null) { - val node = runBlocking { getNodesCase.getNodes(blockchain).firstOrNull()?.firstOrNull() } - if (node != null) { - setCurrentNodeCase.setCurrentNode(blockchain, node) - } - node - } else { - currentNode - }?.url + val blockchain = originalRequest.url.host.toChain() ?: return chain.proceed(originalRequest) + val url = blockchain.getNodeUrl(getNodesCase, getCurrentNodeCase, setCurrentNodeCase) if (url != null) { val httpUrl = url.toHttpUrlOrNull()!! diff --git a/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/TransactionDetails.kt b/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/TransactionDetails.kt index e5b7d4fcc..07b108676 100644 --- a/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/TransactionDetails.kt +++ b/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/TransactionDetails.kt @@ -111,8 +111,13 @@ private fun LazyListScope.transactionItemHead(model: TxDetailsScreenModel) { TransactionType.TransferNFT, TransactionType.Transfer -> model.cryptoAmount TransactionType.AssetActivation, + TransactionType.SmartContractCall, + TransactionType.PerpetualOpenPosition, + TransactionType.PerpetualClosePosition, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, TransactionType.TokenApproval -> model.asset.symbol - TransactionType.SmartContractCall -> TODO() + }, equivalent = when (model.type) { TransactionType.StakeDelegate, @@ -124,8 +129,13 @@ private fun LazyListScope.transactionItemHead(model: TxDetailsScreenModel) { TransactionType.Transfer -> model.fiatAmount TransactionType.AssetActivation, TransactionType.TransferNFT, + TransactionType.SmartContractCall, + TransactionType.PerpetualOpenPosition, + TransactionType.PerpetualClosePosition, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, TransactionType.TokenApproval -> null - TransactionType.SmartContractCall -> TODO() + }, ) } @@ -181,6 +191,10 @@ private fun LazyListScope.transactionRecipientItem(model: TxDetailsScreenModel) TransactionType.StakeRedelegate, TransactionType.AssetActivation, TransactionType.SmartContractCall, + TransactionType.PerpetualOpenPosition, + TransactionType.PerpetualClosePosition, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, TransactionType.StakeWithdraw -> return TransactionType.Transfer, diff --git a/features/asset/presents/src/main/kotlin/com/gemwallet/features/asset/presents/chart/views/PeriodsPanel.kt b/features/asset/presents/src/main/kotlin/com/gemwallet/features/asset/presents/chart/views/PeriodsPanel.kt index 9496ca983..966a21a0a 100644 --- a/features/asset/presents/src/main/kotlin/com/gemwallet/features/asset/presents/chart/views/PeriodsPanel.kt +++ b/features/asset/presents/src/main/kotlin/com/gemwallet/features/asset/presents/chart/views/PeriodsPanel.kt @@ -77,7 +77,6 @@ private fun ChartPeriod.getLabel(): String? { ChartPeriod.Month -> R.string.charts_month ChartPeriod.Year -> R.string.charts_year ChartPeriod.All -> R.string.charts_all - ChartPeriod.Quarter -> return null } return stringResource(id = strId) } \ No newline at end of file diff --git a/features/banner/presents/src/main/kotlin/com/gemwallet/features/banner/presents/views/BannersScene.kt b/features/banner/presents/src/main/kotlin/com/gemwallet/features/banner/presents/views/BannersScene.kt index 487fac354..1eda3008a 100644 --- a/features/banner/presents/src/main/kotlin/com/gemwallet/features/banner/presents/views/BannersScene.kt +++ b/features/banner/presents/src/main/kotlin/com/gemwallet/features/banner/presents/views/BannersScene.kt @@ -83,6 +83,8 @@ fun BannersScene( stringResource(R.string.transfer_activate_asset_title), stringResource(R.string.banner_activate_asset_description, asset?.name ?: "", asset?.id?.chain?.asset()?.name ?: ""), ) + + BannerEvent.SuspiciousAsset -> TODO() } BannerText( title = title, diff --git a/features/earn/stake/viewmodels/src/main/kotlin/com/gemwallet/features/stake/viewmodels/StakeViewModel.kt b/features/earn/stake/viewmodels/src/main/kotlin/com/gemwallet/features/stake/viewmodels/StakeViewModel.kt index 328470e9b..35c4edfcf 100644 --- a/features/earn/stake/viewmodels/src/main/kotlin/com/gemwallet/features/stake/viewmodels/StakeViewModel.kt +++ b/features/earn/stake/viewmodels/src/main/kotlin/com/gemwallet/features/stake/viewmodels/StakeViewModel.kt @@ -98,15 +98,15 @@ class StakeViewModel @Inject constructor( fun onRewards(onConfirm: (ConfirmParams) -> Unit) { val assetInfo = assetInfo.value ?: return val account = account.value ?: return - val validatorsId = delegations.value.filter { BigInteger(it.base.rewards) > BigInteger.ZERO } - .map { it.base.validatorId } + val validators = delegations.value.filter { BigInteger(it.base.rewards) > BigInteger.ZERO } + .map { it.validator } .toSet() .toList() onConfirm( ConfirmParams.Stake.RewardsParams( asset = assetInfo.asset, from = account, - validatorsId = validatorsId, + validators = validators, amount = rewardsAmount.value ) ) diff --git a/features/settings/networks/presents/src/main/kotlin/com/gemwallet/features/settings/networks/presents/NodeItem.kt b/features/settings/networks/presents/src/main/kotlin/com/gemwallet/features/settings/networks/presents/NodeItem.kt index b1a9630e8..8441f24d3 100644 --- a/features/settings/networks/presents/src/main/kotlin/com/gemwallet/features/settings/networks/presents/NodeItem.kt +++ b/features/settings/networks/presents/src/main/kotlin/com/gemwallet/features/settings/networks/presents/NodeItem.kt @@ -55,7 +55,7 @@ internal fun NodeItem( ) }, subtitle = { - val blockNumber = nodeStatus?.blockNumber?.takeIf { !it.isEmpty() }?.let { + val blockNumber = nodeStatus?.blockNumber?.takeIf { it > 0UL }?.let { DecimalFormat.getInstance().format(nodeStatus.blockNumber.toLong()) } ?: "" @@ -89,8 +89,8 @@ private fun NodeItemStatus(nodeStatus: NodeStatus?) { val color = when { nodeStatus?.loading == true -> Color.Transparent nodeStatus?.inSync == true -> when { - nodeStatus.latency < 1024 -> MaterialTheme.colorScheme.tertiary - nodeStatus.latency < 2048 -> Color(0xffff9314) + nodeStatus.latency < 1024UL -> MaterialTheme.colorScheme.tertiary + nodeStatus.latency < 2048UL -> Color(0xffff9314) else -> MaterialTheme.colorScheme.error } else -> MaterialTheme.colorScheme.error @@ -102,7 +102,7 @@ private fun NodeItemStatus(nodeStatus: NodeStatus?) { verticalAlignment = Alignment.CenterVertically, ) { val text = if (nodeStatus?.inSync == true) { - stringResource(R.string.common_latency_in_ms, nodeStatus.latency) + stringResource(R.string.common_latency_in_ms, nodeStatus.latency.toLong()) } else { stringResource(R.string.errors_error) } @@ -132,9 +132,9 @@ fun NodeItemPreview() { nodeStatus = NodeStatus( url = "", chainId = Chain.Ethereum.string, - blockNumber = "123902302938", + blockNumber = 123902302938UL, inSync = true, - latency = 440, + latency = 440UL, loading = false, ) ) { } diff --git a/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/AddNodeViewModel.kt b/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/AddNodeViewModel.kt index b7f2ad39e..f7a3c4968 100644 --- a/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/AddNodeViewModel.kt +++ b/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/AddNodeViewModel.kt @@ -5,7 +5,7 @@ import android.webkit.URLUtil import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.gemwallet.android.blockchain.clients.NodeStatusClientProxy +import com.gemwallet.android.blockchain.services.NodeStatusService import com.gemwallet.android.cases.nodes.AddNodeCase import com.gemwallet.android.cases.nodes.SetCurrentNodeCase import com.gemwallet.android.model.NodeStatus @@ -24,7 +24,7 @@ import javax.inject.Inject @HiltViewModel class AddNodeViewModel @Inject constructor( - private val nodeStatusClient: NodeStatusClientProxy, + private val nodeStatusClient: NodeStatusService, private val addNodeCase: AddNodeCase, private val setCurrentNodeCase: SetCurrentNodeCase, ) : ViewModel() { diff --git a/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/NetworksViewModel.kt b/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/NetworksViewModel.kt index 1c1f380f9..1c6947088 100644 --- a/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/NetworksViewModel.kt +++ b/features/settings/networks/viewmodels/src/main/kotlin/com/gemwallet/features/settings/networks/viewmodels/NetworksViewModel.kt @@ -4,7 +4,7 @@ import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.runtime.snapshotFlow import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.gemwallet.android.blockchain.clients.NodeStatusClientProxy +import com.gemwallet.android.blockchain.services.NodeStatusService import com.gemwallet.android.cases.nodes.GetBlockExplorers import com.gemwallet.android.cases.nodes.GetCurrentBlockExplorer import com.gemwallet.android.cases.nodes.GetCurrentNodeCase @@ -51,7 +51,7 @@ class NetworksViewModel @Inject constructor( private val setBlockExplorerCase: SetBlockExplorerCase, private val getCurrentNodeCase: GetCurrentNodeCase, private val setCurrentNodeCase: SetCurrentNodeCase, - private val nodeStatusClient: NodeStatusClientProxy, + private val nodeStatusClient: NodeStatusService, ) : ViewModel() { private val state = MutableStateFlow(State()) @@ -82,9 +82,9 @@ class NetworksViewModel @Inject constructor( statuses[url] = NodeStatus( url = url, chainId = "", - blockNumber = "", + blockNumber = 0UL, inSync = false, - latency = 0, + latency = 0UL, loading = true, ) } @@ -126,7 +126,7 @@ class NetworksViewModel @Inject constructor( explorers = getBlockExplorers.getBlockExplorers(chain), currentNode = getCurrentNodeCase.getCurrentNode(chain), currentExplorer = getCurrentBlockExplorer.getCurrentBlockExplorer(chain), - availableAddNode = nodeStatusClient.supported(chain), + availableAddNode = true, ) } } diff --git a/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapSelectViewModel.kt b/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapSelectViewModel.kt index 41cc5b6c6..5f18fd4f4 100644 --- a/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapSelectViewModel.kt +++ b/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapSelectViewModel.kt @@ -6,6 +6,7 @@ import com.gemwallet.android.cases.tokens.SearchTokensCase import com.gemwallet.android.data.repositoreis.assets.AssetsRepository import com.gemwallet.android.data.repositoreis.session.SessionRepository import com.gemwallet.android.ext.toAssetId +import com.gemwallet.android.ext.toChain import com.gemwallet.android.ext.toIdentifier import com.gemwallet.android.model.AssetInfo import com.gemwallet.android.model.Session @@ -75,7 +76,7 @@ class SwapSelectSearch( assetsRepository.swapSearch( params.wallet, params.query, - supported.chains.mapNotNull { item -> Chain.entries.firstOrNull { it.string == item } }, + supported.chains.mapNotNull { item -> item.toChain() }, supported.assetIds.mapNotNull { it.toAssetId() } ) } diff --git a/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapViewModel.kt b/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapViewModel.kt index 7a345b966..4c0b079bd 100644 --- a/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/viewmodels/src/main/kotlin/com/gemwallet/features/swap/viewmodels/SwapViewModel.kt @@ -271,17 +271,22 @@ class SwapViewModel @Inject constructor( return ConfirmParams.SwapParams( from = quote.pay.owner!!, fromAsset = quote.pay.asset, - toAssetId = quote.receive.id(), + toAsset = quote.receive.asset, fromAmount = Crypto(fromAmount, quote.pay.asset.decimals).atomicValue, toAmount = BigInteger(quote.quote.toValue), swapData = swapData.data, provider = quote.quote.data.provider.protocol, + providerName = quote.quote.data.provider.name, protocolId = quote.quote.data.provider.protocolId, to = swapData.to, value = swapData.value, approval = swapData.approval?.toModel(), gasLimit = swapData.gasLimit?.toBigIntegerOrNull(), - maxFrom = BigInteger(quote.pay.balance.balance.available) == Crypto(fromAmount, quote.pay.asset.decimals).atomicValue + maxFrom = BigInteger(quote.pay.balance.balance.available) == Crypto(fromAmount, quote.pay.asset.decimals).atomicValue, + etaInSeconds = quote.quote.etaInSeconds, + slippageBps = quote.quote.data.slippageBps, + walletAddress = quote.pay.owner?.address!!, + ) } diff --git a/features/transfer_amount/presents/src/main/kotlin/com/gemwallet/features/transfer_amount/presents/views/AmountScene.kt b/features/transfer_amount/presents/src/main/kotlin/com/gemwallet/features/transfer_amount/presents/views/AmountScene.kt index 0b741dc2f..a46529a43 100644 --- a/features/transfer_amount/presents/src/main/kotlin/com/gemwallet/features/transfer_amount/presents/views/AmountScene.kt +++ b/features/transfer_amount/presents/src/main/kotlin/com/gemwallet/features/transfer_amount/presents/views/AmountScene.kt @@ -155,4 +155,8 @@ private fun getTitle(txType: TransactionType) = when (txType) { TransactionType.StakeRewards -> stringResource(id = R.string.transfer_rewards_title) TransactionType.AssetActivation -> stringResource(id = R.string.transfer_activate_asset_title) TransactionType.SmartContractCall -> stringResource(id = R.string.transfer_amount_title) + TransactionType.PerpetualOpenPosition -> stringResource(R.string.perpetual_position) + TransactionType.PerpetualClosePosition -> stringResource(R.string.perpetual_close_position) + TransactionType.StakeFreeze -> stringResource(R.string.transfer_freeze_title) + TransactionType.StakeUnfreeze -> stringResource(R.string.transfer_unfreeze_title) } \ No newline at end of file diff --git a/features/transfer_amount/viewmodels/src/main/kotlin/com/gemwallet/features/transfer_amount/viewmodels/AmountViewModel.kt b/features/transfer_amount/viewmodels/src/main/kotlin/com/gemwallet/features/transfer_amount/viewmodels/AmountViewModel.kt index 5e933b914..42b14f1f5 100644 --- a/features/transfer_amount/viewmodels/src/main/kotlin/com/gemwallet/features/transfer_amount/viewmodels/AmountViewModel.kt +++ b/features/transfer_amount/viewmodels/src/main/kotlin/com/gemwallet/features/transfer_amount/viewmodels/AmountViewModel.kt @@ -129,10 +129,14 @@ class AmountViewModel @Inject constructor( TransactionType.StakeUndelegate, TransactionType.StakeRedelegate, TransactionType.StakeWithdraw -> Crypto(BigInteger(delegation?.base?.balance ?: "0")) + TransactionType.PerpetualOpenPosition -> throw IllegalArgumentException() // TODO: HyperCore + TransactionType.PerpetualClosePosition -> throw IllegalArgumentException() // TODO: HyperCore TransactionType.AssetActivation, TransactionType.TransferNFT, TransactionType.SmartContractCall, TransactionType.TokenApproval, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, null -> Crypto(BigInteger.ZERO) } assetInfo.asset.format(value, 8) @@ -247,20 +251,24 @@ class AmountViewModel @Inject constructor( val builder = ConfirmParams.Builder(asset, owner, amount.atomicValue) val nextParams = when (params.txType) { TransactionType.Transfer -> builder.transfer(destination!!, memo, maxAmount.value,) - TransactionType.StakeDelegate -> builder.delegate(validator?.id ?: return) + TransactionType.StakeDelegate -> builder.delegate(validator ?: return) TransactionType.StakeUndelegate -> builder.undelegate(delegation ?: return) TransactionType.StakeRewards -> { val validators = stakeRepository.getRewards(asset.id, owner.address) - .map { it.validator.id } + .map { it.validator } builder.rewards(validators) } - TransactionType.StakeRedelegate -> builder.redelegate(validator?.id!!, delegation!!) + TransactionType.StakeRedelegate -> builder.redelegate(validator!!, delegation!!) TransactionType.StakeWithdraw -> builder.withdraw(delegation!!) TransactionType.AssetActivation -> builder.activate() TransactionType.Swap, TransactionType.TransferNFT, TransactionType.SmartContractCall, - TransactionType.TokenApproval -> throw IllegalArgumentException() + TransactionType.TokenApproval, + TransactionType.PerpetualOpenPosition, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, + TransactionType.PerpetualClosePosition -> throw IllegalArgumentException() } onConfirm(nextParams) } @@ -335,6 +343,10 @@ class AmountViewModel @Inject constructor( TransactionType.StakeWithdraw -> Crypto(BigInteger(delegation?.base?.balance ?: "0")) TransactionType.AssetActivation, TransactionType.TransferNFT, + TransactionType.PerpetualOpenPosition, + TransactionType.PerpetualClosePosition, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, TransactionType.SmartContractCall -> throw IllegalArgumentException() } if (amount.atomicValue > availableAmount.atomicValue) { diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmParamsExt.kt b/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmParamsExt.kt new file mode 100644 index 000000000..3d24439d3 --- /dev/null +++ b/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmParamsExt.kt @@ -0,0 +1,38 @@ +package com.gemwallet.android.domains.confirm + +import com.gemwallet.android.model.ConfirmParams +import uniffi.gemstone.GemApprovalData +import uniffi.gemstone.GemSwapData +import uniffi.gemstone.GemSwapProviderData +import uniffi.gemstone.GemSwapQuote +import uniffi.gemstone.GemSwapQuoteData + +fun ConfirmParams.SwapParams.toGem(): GemSwapData { + return GemSwapData( + quote = GemSwapQuote( + fromValue = fromAmount.toString(), + toValue = toAmount.toString(), + providerData = GemSwapProviderData( + provider = provider, + protocolName = protocolId, + name = providerName, + ), + walletAddress = walletAddress, + slippageBps = slippageBps, + etaInSeconds = etaInSeconds, + ), + data = GemSwapQuoteData( + to = to, + data = swapData, + approval = approval?.let { + GemApprovalData( + token = it.token, + spender = it.spender, + value = it.value + ) + }, + value = value, + gasLimit = gasLimit?.toString() + ) + ) +} \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/domains/stake/DelegationExt.kt b/gemcore/src/main/kotlin/com/gemwallet/android/domains/stake/DelegationExt.kt new file mode 100644 index 000000000..99a4e3013 --- /dev/null +++ b/gemcore/src/main/kotlin/com/gemwallet/android/domains/stake/DelegationExt.kt @@ -0,0 +1,23 @@ +package com.gemwallet.android.domains.stake + +import com.gemwallet.android.ext.toIdentifier +import com.gemwallet.android.model.ConfirmParams +import com.wallet.core.primitives.Delegation +import uniffi.gemstone.GemDelegation +import uniffi.gemstone.GemDelegationBase + +fun Delegation.toGem(chain: uniffi.gemstone.Chain): GemDelegation { + return GemDelegation( + base = GemDelegationBase( + assetId = base.assetId.toIdentifier(), + delegationId = base.delegationId, + validatorId = base.validatorId, + balance = base.balance, + shares = base.shares, + completionDate = base.completionDate?.toULong(), + delegationState = base.state.string, + rewards = base.rewards, + ), + validator = validator.toGem(chain) + ) +} \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/domains/stake/DelegationValidatorExt.kt b/gemcore/src/main/kotlin/com/gemwallet/android/domains/stake/DelegationValidatorExt.kt new file mode 100644 index 000000000..f6f9b5445 --- /dev/null +++ b/gemcore/src/main/kotlin/com/gemwallet/android/domains/stake/DelegationValidatorExt.kt @@ -0,0 +1,15 @@ +package com.gemwallet.android.domains.stake + +import com.wallet.core.primitives.DelegationValidator +import uniffi.gemstone.GemDelegationValidator + +fun DelegationValidator.toGem(chain: uniffi.gemstone.Chain): GemDelegationValidator { + return GemDelegationValidator( + chain = chain, + id = id, + name = name, + isActive = isActive, + commission = commision, + apr = apr, + ) +} \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/ext/Chain.kt b/gemcore/src/main/kotlin/com/gemwallet/android/ext/Chain.kt index b388631fc..b61065bf3 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/ext/Chain.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/ext/Chain.kt @@ -47,6 +47,7 @@ fun Chain.assetType(): AssetType? { Chain.Monad, Chain.World -> AssetType.ERC20 + Chain.HyperCore, Chain.Cosmos, Chain.Osmosis, Chain.Celestia, @@ -103,7 +104,7 @@ fun Chain.Companion.findByString(value: String): Chain? { return Chain.entries.firstOrNull{ it.string == value} } -fun Chain.Companion.exclude() = setOf(Chain.Celo) +fun Chain.Companion.exclude() = setOf(Chain.Celo, Chain.HyperCore) fun Chain.Companion.available() = (Chain.entries.toSet() - exclude()) @@ -118,6 +119,7 @@ fun List.filter(query: String): List { fun Chain.toChainType(): ChainType { return when (this) { + Chain.HyperCore -> ChainType.HyperCore Chain.Solana -> ChainType.Solana Chain.Ton -> ChainType.Ton Chain.Tron -> ChainType.Tron @@ -205,4 +207,8 @@ val Chain.keyEncodingTypes: List Chain.Solana -> listOf(EncodingType.Base58, EncodingType.Hex) Chain.Stellar -> listOf(EncodingType.Base32, EncodingType.Hex) else -> listOf(EncodingType.Hex) - } \ No newline at end of file + } + +fun uniffi.gemstone.Chain.toChain(): Chain? { + return Chain.entries.firstOrNull { it.string == this } +} \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/ext/StakeChain.kt b/gemcore/src/main/kotlin/com/gemwallet/android/ext/StakeChain.kt index cf9d436b3..6cb448d6b 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/ext/StakeChain.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/ext/StakeChain.kt @@ -17,7 +17,8 @@ fun StakeChain.redelegated(): Boolean = when (this) { StakeChain.Solana, StakeChain.Sui, StakeChain.SmartChain, - StakeChain.Tron -> false + StakeChain.Tron, + StakeChain.HyperCore -> false } fun StakeChain.withdraw(): Boolean = when (this) { @@ -28,6 +29,7 @@ fun StakeChain.withdraw(): Boolean = when (this) { StakeChain.Osmosis, StakeChain.SmartChain, StakeChain.Tron, + StakeChain.HyperCore, StakeChain.Sui-> false StakeChain.Solana -> true } @@ -41,5 +43,6 @@ fun StakeChain.claimed(): Boolean = when (this) { StakeChain.Solana, StakeChain.Sui, StakeChain.SmartChain, + StakeChain.HyperCore, StakeChain.Tron -> false } \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/model/AssetBalance.kt b/gemcore/src/main/kotlin/com/gemwallet/android/model/AssetBalance.kt index dcbcfcdfd..156071044 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/model/AssetBalance.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/model/AssetBalance.kt @@ -42,7 +42,7 @@ data class AssetBalance( reserved: String = "0", isActive: Boolean = true, ): AssetBalance { - val balance = Balance( + val balance = Balance( // TODO: Check number is correct available = available, frozen = frozen, locked = locked, diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/model/ConfirmParams.kt b/gemcore/src/main/kotlin/com/gemwallet/android/model/ConfirmParams.kt index 801ef9bc4..251e9c875 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/model/ConfirmParams.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/model/ConfirmParams.kt @@ -11,6 +11,7 @@ import com.wallet.core.primitives.Asset import com.wallet.core.primitives.AssetId import com.wallet.core.primitives.AssetSubtype import com.wallet.core.primitives.Delegation +import com.wallet.core.primitives.DelegationValidator import com.wallet.core.primitives.NFTAsset import com.wallet.core.primitives.TransactionType import kotlinx.serialization.Serializable @@ -60,16 +61,15 @@ sealed class ConfirmParams { return TokenApprovalParams(asset, from, approvalData, provider, contract) } - fun delegate(validatorId: String) = Stake.DelegateParams(asset, from, amount, validatorId) + fun delegate(validator: DelegationValidator) = Stake.DelegateParams(asset, from, amount, validator) - fun rewards(validatorsId: List) = Stake.RewardsParams(asset, from, validatorsId, amount) + fun rewards(validators: List) = Stake.RewardsParams(asset, from, validators, amount) fun withdraw(delegation: Delegation) = Stake.WithdrawParams( asset = asset, from = from, amount = amount, - validatorId = delegation.validator.id, - delegationId = delegation.base.delegationId, + delegation = delegation, ) fun undelegate(delegation: Delegation): Stake.UndelegateParams { @@ -77,20 +77,17 @@ sealed class ConfirmParams { asset, from, amount, - delegation.validator.id, - delegation.base.delegationId, - delegation.base.shares, - delegation.base.balance + delegation, ) } - fun redelegate(dstValidatorId: String, delegation: Delegation): Stake.RedelegateParams { + fun redelegate(dstValidator: DelegationValidator, delegation: Delegation): Stake.RedelegateParams { return Stake.RedelegateParams( asset, from = from, amount, - delegation.validator.id, - dstValidatorId, + delegation, + dstValidator, delegation.base.shares, delegation.base.balance, ) @@ -129,6 +126,14 @@ sealed class ConfirmParams { override val memo: String? = null, override val isMaxAmount: Boolean = false, override val inputType: InputType? = null, + val name: String, + val description: String, + val url: String, + val icon: String, + val redirectNative: String?, + val redirectUniversal: String?, + val gasLimit: String?, + val gasPrice: String?, ) : TransferParams() @Serializable @@ -172,6 +177,10 @@ sealed class ConfirmParams { get() = BigInteger.ZERO override fun memo(): String? = data + + override fun destination(): DestinationAddress? { + return DestinationAddress(contract) + } } @Serializable @@ -179,26 +188,34 @@ sealed class ConfirmParams { override val from: Account, val fromAsset: Asset, @Serializable(BigIntegerSerializer::class) val fromAmount: BigInteger, - val toAssetId: AssetId, + val toAsset: Asset, @Serializable(BigIntegerSerializer::class) val toAmount: BigInteger, val swapData: String, val provider: String, + val providerName: String, val protocolId: String, val to: String, val value: String, val approval: ApprovalData? = null, + val slippageBps: UInt, + val etaInSeconds: UInt?, + val walletAddress: String, @Serializable(BigIntegerSerializer::class) val gasLimit: BigInteger? = null, val maxFrom: Boolean = false, ) : ConfirmParams() { override val asset: Asset get() = fromAsset + override val amount: BigInteger get() = fromAmount + override fun destination(): DestinationAddress = DestinationAddress(to) override fun isMax(): Boolean = maxFrom + override fun memo(): String? = swapData + @Serializable data class ApprovalData( val token: String, @@ -212,7 +229,11 @@ sealed class ConfirmParams { override val asset: Asset, override val from: Account, @Serializable(BigIntegerSerializer::class) override val amount: BigInteger = BigInteger.ZERO, - ) : ConfirmParams() + ) : ConfirmParams() { + override fun destination(): DestinationAddress? { + return DestinationAddress(from.address) + } + } @Serializable class NftParams( @@ -230,57 +251,68 @@ sealed class ConfirmParams { @Serializable sealed class Stake : ConfirmParams() { - abstract val validatorId: String @Serializable class DelegateParams( override val asset: Asset, override val from: Account, @Serializable(BigIntegerSerializer::class) override val amount: BigInteger, - override val validatorId: String, - ) : Stake() + val validator: DelegationValidator, + ) : Stake() { + override fun destination(): DestinationAddress? { + return DestinationAddress(validator.id) + } + } @Serializable class WithdrawParams( override val asset: Asset, override val from: Account, @Serializable(BigIntegerSerializer::class) override val amount: BigInteger, - override val validatorId: String, - val delegationId: String, - ) : Stake() + val delegation: Delegation, + ) : Stake() { + override fun destination(): DestinationAddress? { + return DestinationAddress(delegation.validator.id) + } + } @Serializable class UndelegateParams( override val asset: Asset, override val from: Account, @Serializable(BigIntegerSerializer::class) override val amount: BigInteger, - override val validatorId: String, - val delegationId: String, - val share: String?, - val balance: String? - ) : Stake() + val delegation: Delegation, + ) : Stake() { + override fun destination(): DestinationAddress? { + return DestinationAddress(delegation.validator.id) + } + } @Serializable class RedelegateParams( override val asset: Asset, override val from: Account, @Serializable(BigIntegerSerializer::class) override val amount: BigInteger, - val srcValidatorId: String, - val dstValidatorId: String, + val delegation: Delegation, + val dstValidator: DelegationValidator, val share: String?, val balance: String?, ) : Stake() { - override val validatorId: String = "" + override fun destination(): DestinationAddress? { + return DestinationAddress("") + } } @Serializable class RewardsParams( override val asset: Asset, override val from: Account, - val validatorsId: List, + val validators: List, @Serializable(BigIntegerSerializer::class) override val amount: BigInteger, ) : Stake() { - override val validatorId: String = "" + override fun destination(): DestinationAddress? { + return DestinationAddress("") + } } } @@ -305,7 +337,7 @@ sealed class ConfirmParams { } } - open fun destination(): DestinationAddress? = null + open fun destination(): DestinationAddress? = null open fun memo(): String? = null diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/model/NodeStatus.kt b/gemcore/src/main/kotlin/com/gemwallet/android/model/NodeStatus.kt index 7e38b6b4f..171f76945 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/model/NodeStatus.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/model/NodeStatus.kt @@ -3,8 +3,8 @@ package com.gemwallet.android.model data class NodeStatus( val url: String, val chainId: String, - val blockNumber: String, + val blockNumber: ULong, val inSync: Boolean, - val latency: Long, + val latency: ULong, val loading: Boolean = false, ) \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/model/SignerParams.kt b/gemcore/src/main/kotlin/com/gemwallet/android/model/SignerParams.kt index 0c6984617..9645c7075 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/model/SignerParams.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/model/SignerParams.kt @@ -1,22 +1,33 @@ package com.gemwallet.android.model import com.wallet.core.primitives.FeePriority -import com.wallet.core.primitives.ScanTransaction import java.math.BigInteger data class SignerParams( val input: ConfirmParams, - val chainData: ChainSignData, +// val chainData: ChainSignData, +// private val fee: List, + val data: List, val finalAmount: BigInteger = BigInteger.ZERO, - val scanTransaction: ScanTransaction? = null, -) +) { + fun fee(priority: FeePriority = FeePriority.Normal): Fee { + return data.firstOrNull { it.fee.priority == priority }?.fee ?: data.first().fee + } -interface ChainSignData { - fun fee(speed: FeePriority = FeePriority.Normal): Fee + fun data(priority: FeePriority = FeePriority.Normal): Data { + return data.firstOrNull { it.fee.priority == priority } ?: data.first() + } fun gasFee(feePriority: FeePriority = FeePriority.Normal): GasFee = (fee(feePriority) as? GasFee) ?: throw Exception("Fee error: wait gas fee") - fun allFee(): List = emptyList() + fun allFee(): List = data.map { it.fee } + + data class Data( + val fee: Fee, + val chainData: ChainSignData, + ) +} +interface ChainSignData { fun blockNumber(): String = "" } \ No newline at end of file diff --git a/gemcore/src/main/kotlin/com/gemwallet/android/model/Transaction.kt b/gemcore/src/main/kotlin/com/gemwallet/android/model/Transaction.kt index fa81508f7..c1aad7887 100644 --- a/gemcore/src/main/kotlin/com/gemwallet/android/model/Transaction.kt +++ b/gemcore/src/main/kotlin/com/gemwallet/android/model/Transaction.kt @@ -4,9 +4,9 @@ import com.gemwallet.android.serializer.DateSerializer import com.gemwallet.android.serializer.JsonAsStringSerializer import com.wallet.core.primitives.AssetId import com.wallet.core.primitives.TransactionDirection -import com.wallet.core.primitives.TransactionInput import com.wallet.core.primitives.TransactionState import com.wallet.core.primitives.TransactionType +import com.wallet.core.primitives.TransactionUtxoInput import kotlinx.serialization.Serializable @Serializable @@ -26,10 +26,9 @@ data class Transaction ( val value: String, val memo: String? = null, val direction: TransactionDirection, - val utxoInputs: List, - val utxoOutputs: List, - @Serializable(with = JsonAsStringSerializer::class) - val metadata: String? = null, + val utxoInputs: List, + val utxoOutputs: List, + @Serializable(with = JsonAsStringSerializer::class) val metadata: String? = null, @Serializable(with = DateSerializer::class) val createdAt: Long, ) diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/AddressStatus.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/AddressStatus.kt new file mode 100644 index 000000000..8a09318f2 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/AddressStatus.kt @@ -0,0 +1,15 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class AddressStatus(val string: String) { + @SerialName("multiSignature") + MultiSignature("multiSignature"), +} + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetPrice.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetPrice.kt index 91b22b229..9715388db 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetPrice.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetPrice.kt @@ -63,8 +63,6 @@ enum class ChartPeriod(val string: String) { Week("week"), @SerialName("month") Month("month"), - @SerialName("quarter") - Quarter("quarter"), @SerialName("year") Year("year"), @SerialName("all") diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetType.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetType.kt index db5364d0f..2bad07c29 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetType.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/AssetType.kt @@ -25,6 +25,8 @@ enum class AssetType(val string: String) { BEP20("BEP20"), @SerialName("SPL") SPL("SPL"), + @SerialName("SPL2022") + SPL2022("SPL2022"), @SerialName("TRC20") TRC20("TRC20"), @SerialName("TOKEN") @@ -37,5 +39,7 @@ enum class AssetType(val string: String) { SYNTH("SYNTH"), @SerialName("ASA") ASA("ASA"), + @SerialName("PERPETUAL") + PERPETUAL("PERPETUAL"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Banner.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Banner.kt index 8e360a4d5..7e2e0b1fd 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Banner.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Banner.kt @@ -19,6 +19,8 @@ enum class BannerEvent(val string: String) { AccountBlockedMultiSignature("accountBlockedMultiSignature"), @SerialName("activateAsset") ActivateAsset("activateAsset"), + @SerialName("suspiciousAsset") + SuspiciousAsset("suspiciousAsset"), } @Serializable diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/BroadcastOptions.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/BroadcastOptions.kt new file mode 100644 index 000000000..e3463a928 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/BroadcastOptions.kt @@ -0,0 +1,14 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +data class BroadcastOptions ( + val skipPreflight: Boolean +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Chain.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Chain.kt index 9148e7ba1..1416ae3e3 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Chain.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Chain.kt @@ -99,6 +99,8 @@ enum class Chain(val string: String) { Unichain("unichain"), @SerialName("hyperliquid") Hyperliquid("hyperliquid"), + @SerialName("hypercore") + HyperCore("hypercore"), @SerialName("monad") Monad("monad"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainStake.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainStake.kt index 4f06438d7..8a9169e44 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainStake.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainStake.kt @@ -27,5 +27,7 @@ enum class StakeChain(val string: String) { SmartChain("smartchain"), @SerialName("tron") Tron("tron"), + @SerialName("hypercore") + HyperCore("hypercore"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainType.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainType.kt index eee96900f..149f7a6db 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainType.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/ChainType.kt @@ -37,5 +37,7 @@ enum class ChainType(val string: String) { Polkadot("polkadot"), @SerialName("cardano") Cardano("cardano"), + @SerialName("hypercore") + HyperCore("hypercore"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Chart.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Chart.kt new file mode 100644 index 000000000..65ee782e3 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Chart.kt @@ -0,0 +1,25 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +data class ChartCandleStick ( + val date: SerializedDate, + val open: Double, + val high: Double, + val low: Double, + val close: Double, + val volume: Double +) + +@Serializable +data class ChartDateValue ( + val date: SerializedDate, + val value: Double +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Delegation.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Delegation.kt index a1db1b533..27960c3f3 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Delegation.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Delegation.kt @@ -32,7 +32,7 @@ data class DelegationBase ( val balance: String, val shares: String, val rewards: String, - val completionDate: Long? = null, + val completionDate: SerializedDate? = null, val delegationId: String, val validatorId: String ) diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Device.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Device.kt index d86016413..b0930fd5f 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Device.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Device.kt @@ -11,6 +11,8 @@ import kotlinx.serialization.SerialName data class Device ( val id: String, val platform: Platform, + val os: String? = null, + val model: String? = null, val platformStore: PlatformStore? = null, val token: String, val locale: String, diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/FeePriorityValue.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/FeePriorityValue.kt new file mode 100644 index 000000000..398e220f3 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/FeePriorityValue.kt @@ -0,0 +1,15 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +data class PriorityFeeValue ( + val priority: FeePriority, + val value: String +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/FiatQuoteRequest.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/FiatQuoteRequest.kt index c68494cad..98d4224ba 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/FiatQuoteRequest.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/FiatQuoteRequest.kt @@ -11,7 +11,7 @@ import kotlinx.serialization.SerialName data class FiatQuoteRequest ( val assetId: String, val type: FiatQuoteType, - val fiatCurrency: String, + val fiatCurrency: Currency, val fiatAmount: Double? = null, val cryptoValue: String? = null, val walletAddress: String diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/LatencyType.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/LatencyType.kt new file mode 100644 index 000000000..992162d28 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/LatencyType.kt @@ -0,0 +1,25 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class LatencyType(val string: String) { + @SerialName("Fast") + Fast("Fast"), + @SerialName("Normal") + Normal("Normal"), + @SerialName("Slow") + Slow("Slow"), +} + +@Serializable +data class Latency ( + val latency_type: LatencyType, + val value: Double +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Name.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Name.kt index 884041681..795683343 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Name.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Name.kt @@ -47,5 +47,7 @@ enum class NameProvider(val string: String) { Basenames("basenames"), @SerialName("hyperliquid") Hyperliquid("hyperliquid"), + @SerialName("alldomains") + AllDomains("alldomains"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/PaymentType.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/PaymentType.kt new file mode 100644 index 000000000..bf812d06d --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/PaymentType.kt @@ -0,0 +1,19 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class PaymentType(val string: String) { + @SerialName("card") + Card("card"), + @SerialName("google_pay") + GooglePay("google_pay"), + @SerialName("apple_pay") + ApplePay("apple_pay"), +} + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/PerpetualPosition.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/PerpetualPosition.kt new file mode 100644 index 000000000..a5b39fde7 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/PerpetualPosition.kt @@ -0,0 +1,45 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class PerpetualMarginType(val string: String) { + @SerialName("cross") + Cross("cross"), + @SerialName("isolated") + Isolated("isolated"), +} + +@Serializable +data class PriceTarget ( + val price: Double? = null, + val percentage: Double? = null +) + +@Serializable +enum class PerpetualDirection // TODO: It's stub wait fix + +@Serializable +data class PerpetualPosition ( + val id: String, + val perpetualId: String, + val assetId: AssetId, + val size: Double, + val sizeValue: Double, + val leverage: UByte, + val entryPrice: Double? = null, + val liquidationPrice: Double? = null, + val marginType: PerpetualMarginType, + val direction: PerpetualDirection, + val marginAmount: Double, + val takeProfit: PriceTarget? = null, + val stopLoss: PriceTarget? = null, + val pnl: Double, + val funding: Float? = null +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/PerpetualProvider.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/PerpetualProvider.kt new file mode 100644 index 000000000..c71a9fcf6 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/PerpetualProvider.kt @@ -0,0 +1,15 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class PerpetualProvider(val string: String) { + @SerialName("hypercore") + Hypercore("hypercore"), +} + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/PushNotification.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/PushNotification.kt index 82e1c415f..8f1f691fd 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/PushNotification.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/PushNotification.kt @@ -26,6 +26,8 @@ enum class PushNotificationTypes(val string: String) { BuyAsset("buyAsset"), @SerialName("swapAsset") SwapAsset("swapAsset"), + @SerialName("support") + Support("support"), } @Serializable @@ -33,6 +35,9 @@ data class PushNotificationPayloadType ( val type: PushNotificationTypes ) +@Serializable +object PushNotificationSupport + @Serializable data class PushNotificationSwapAsset ( val fromAssetId: String, diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Scan.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Scan.kt index f8ffa3c4d..0be6ab12c 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Scan.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Scan.kt @@ -7,6 +7,27 @@ package com.wallet.core.primitives import kotlinx.serialization.Serializable import kotlinx.serialization.SerialName +@Serializable +enum class AddressType(val string: String) { + @SerialName("address") + Address("address"), + @SerialName("contract") + Contract("contract"), + @SerialName("validator") + Validator("validator"), +} + +@Serializable +data class ScanAddress ( + val chain: Chain, + val address: String, + val name: String? = null, + val type: AddressType? = null, + val isMalicious: Boolean? = null, + val isMemoRequired: Boolean? = null, + val isVerified: Boolean? = null +) + @Serializable data class ScanAddressTarget ( val chain: Chain, diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/SolanaTypes.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/SolanaTypes.kt new file mode 100644 index 000000000..760fe2eac --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/SolanaTypes.kt @@ -0,0 +1,23 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +data class SolanaAccountMeta ( + val pubkey: String, + val isSigner: Boolean, + val isWritable: Boolean +) + +@Serializable +data class SolanaInstruction ( + val programId: String, + val accounts: List, + val data: String +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/StakeType.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/StakeType.kt new file mode 100644 index 000000000..6e3d706bd --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/StakeType.kt @@ -0,0 +1,65 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class FreezeType(val string: String) { + @SerialName("Freeze") + Freeze("Freeze"), + @SerialName("Unfreeze") + Unfreeze("Unfreeze"), +} + +@Serializable +enum class Resource(val string: String) { + @SerialName("bandwidth") + Bandwidth("bandwidth"), + @SerialName("energy") + Energy("energy"), +} + +@Serializable +data class FreezeData ( + val freezeType: FreezeType, + val resource: Resource +) + +@Serializable +data class RedelegateData ( + val delegation: Delegation, + val toValidator: DelegationValidator +) + +@Serializable +data class StakeData ( + val data: String? = null, + val to: String? = null, +) + +@Serializable +sealed class StakeType { + @Serializable + @SerialName("Stake") + data class Stake(val content: DelegationValidator): StakeType() + @Serializable + @SerialName("Unstake") + data class Unstake(val content: Delegation): StakeType() + @Serializable + @SerialName("Redelegate") + data class Redelegate(val content: RedelegateData): StakeType() + @Serializable + @SerialName("Rewards") + data class Rewards(val content: List): StakeType() + @Serializable + @SerialName("Withdraw") + data class Withdraw(val content: Delegation): StakeType() + @Serializable + @SerialName("Freeze") + data class Freeze(val content: FreezeData): StakeType() +} + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Support.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Support.kt new file mode 100644 index 000000000..370a53ac8 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Support.kt @@ -0,0 +1,16 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +data class SupportDevice ( + val supportId: String, + val deviceId: String, + val unread: Int +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/SwapProvider.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/SwapProvider.kt index 773cd04d3..b7cd2edea 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/SwapProvider.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/SwapProvider.kt @@ -21,8 +21,6 @@ enum class SwapProvider(val string: String) { PancakeswapAptosV2("pancakeswap_aptos_v2"), @SerialName("thorchain") Thorchain("thorchain"), - @SerialName("orca") - Orca("orca"), @SerialName("jupiter") Jupiter("jupiter"), @SerialName("across") diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/Transaction.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/Transaction.kt index 0da44f0d5..71f82ac90 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/Transaction.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/Transaction.kt @@ -24,8 +24,8 @@ data class Transaction ( val value: String, val memo: String? = null, val direction: TransactionDirection, - val utxoInputs: List, - val utxoOutputs: List, + val utxoInputs: List, + val utxoOutputs: List, val metadata: String?? = null, val createdAt: SerializedDate ) diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionMetadataTypes.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionMetadataTypes.kt index 162d45a23..9499b5fc2 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionMetadataTypes.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionMetadataTypes.kt @@ -13,6 +13,12 @@ data class TransactionNFTTransferMetadata ( val name: String? = null ) +@Serializable +data class TransactionPerpetualMetadata ( + val pnl: Double, + val price: Double +) + @Serializable data class TransactionSwapMetadata ( val fromAsset: AssetId, diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionType.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionType.kt index 607a298fb..7ffe65332 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionType.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionType.kt @@ -27,9 +27,17 @@ enum class TransactionType(val string: String) { StakeRedelegate("stakeRedelegate"), @SerialName("stakeWithdraw") StakeWithdraw("stakeWithdraw"), + @SerialName("stakeFreeze") + StakeFreeze("stakeFreeze"), + @SerialName("stakeUnfreeze") + StakeUnfreeze("stakeUnfreeze"), @SerialName("assetActivation") AssetActivation("assetActivation"), @SerialName("smartContractCall") SmartContractCall("smartContractCall"), + @SerialName("perpetualOpenPosition") + PerpetualOpenPosition("perpetualOpenPosition"), + @SerialName("perpetualClosePosition") + PerpetualClosePosition("perpetualClosePosition"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionUtxo.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionUtxo.kt index 2ecbe2439..d93ebb2f0 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionUtxo.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionUtxo.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.SerialName @Serializable -data class TransactionInput ( +data class TransactionUtxoInput ( val address: String, val value: String ) diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionWallet.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionWallet.kt new file mode 100644 index 000000000..494040467 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/TransactionWallet.kt @@ -0,0 +1,15 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +data class TransactionWallet ( + val transaction: Transaction, + val wallet: Wallet +) + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnectBlockchainMethods.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnectBlockchainMethods.kt new file mode 100644 index 000000000..ccde447f7 --- /dev/null +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnectBlockchainMethods.kt @@ -0,0 +1,45 @@ +/** + * Generated by typeshare 1.13.2 + */ + +package com.wallet.core.primitives + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +@Serializable +enum class WalletConnectEthereumMethods(val string: String) { + @SerialName("chainId") + chain_id("chainId"), + @SerialName("sign") + sign("sign"), + @SerialName("personalSign") + personal_sign("personalSign"), + @SerialName("signTypedData") + sign_typed_data("signTypedData"), + @SerialName("signTypedDataV4") + sign_typed_data_v4("signTypedDataV4"), + @SerialName("signTransaction") + sign_transaction("signTransaction"), + @SerialName("sendTransaction") + send_transaction("sendTransaction"), + @SerialName("sendRawTransaction") + send_raw_transaction("sendRawTransaction"), + @SerialName("switchChain") + switch_chain("switchChain"), + @SerialName("addChain") + add_chain("addChain"), +} + +@Serializable +enum class WalletConnectSolanaMethods(val string: String) { + @SerialName("signMessage") + sign_message("signMessage"), + @SerialName("signTransaction") + sign_transaction("signTransaction"), + @SerialName("signAndSendTransaction") + sign_and_send_transaction("signAndSendTransaction"), + @SerialName("signAllTransactions") + sign_all_transactions("signAllTransactions"), +} + diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnector.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnector.kt index 899065a2c..e96802040 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnector.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/WalletConnector.kt @@ -54,44 +54,44 @@ data class WalletConnectionSessionProposal ( @Serializable enum class WalletConnectionEvents(val string: String) { @SerialName("connect") - connect("connect"), + Connect("connect"), @SerialName("disconnect") - disconnect("disconnect"), + Disconnect("disconnect"), @SerialName("accountsChanged") - accounts_changed("accountsChanged"), + AccountsChanged("accountsChanged"), @SerialName("chainChanged") - chain_changed("chainChanged"), + ChainChanged("chainChanged"), } @Serializable enum class WalletConnectionMethods(val string: String) { @SerialName("eth_chainId") - eth_chain_id("eth_chainId"), + EthChainId("eth_chainId"), @SerialName("eth_sign") - eth_sign("eth_sign"), + EthSign("eth_sign"), @SerialName("personal_sign") - personal_sign("personal_sign"), + PersonalSign("personal_sign"), @SerialName("eth_signTypedData") - eth_sign_typed_data("eth_signTypedData"), + EthSignTypedData("eth_signTypedData"), @SerialName("eth_signTypedData_v4") - eth_sign_typed_data_v4("eth_signTypedData_v4"), + EthSignTypedDataV4("eth_signTypedData_v4"), @SerialName("eth_signTransaction") - eth_sign_transaction("eth_signTransaction"), + EthSignTransaction("eth_signTransaction"), @SerialName("eth_sendTransaction") - eth_send_transaction("eth_sendTransaction"), + EthSendTransaction("eth_sendTransaction"), @SerialName("eth_sendRawTransaction") - eth_send_raw_transaction("eth_sendRawTransaction"), + EthSendRawTransaction("eth_sendRawTransaction"), @SerialName("wallet_switchEthereumChain") - wallet_switch_ethereum_chain("wallet_switchEthereumChain"), + WalletSwitchEthereumChain("wallet_switchEthereumChain"), @SerialName("wallet_addEthereumChain") - wallet_add_ethereum_chain("wallet_addEthereumChain"), + WalletAddEthereumChain("wallet_addEthereumChain"), @SerialName("solana_signMessage") - solana_sign_message("solana_signMessage"), + SolanaSignMessage("solana_signMessage"), @SerialName("solana_signTransaction") - solana_sign_transaction("solana_signTransaction"), + SolanaSignTransaction("solana_signTransaction"), @SerialName("solana_signAndSendTransaction") - solana_sign_and_send_transaction("solana_signAndSendTransaction"), + SolanaSignAndSendTransaction("solana_signAndSendTransaction"), @SerialName("solana_signAllTransactions") - solana_sign_all_transactions("solana_signAllTransactions"), + SolanaSignAllTransactions("solana_signAllTransactions"), } diff --git a/gemcore/src/main/kotlin/com/wallet/core/primitives/swap/Approval.kt b/gemcore/src/main/kotlin/com/wallet/core/primitives/swap/Approval.kt index cfd694416..398ead729 100644 --- a/gemcore/src/main/kotlin/com/wallet/core/primitives/swap/Approval.kt +++ b/gemcore/src/main/kotlin/com/wallet/core/primitives/swap/Approval.kt @@ -6,6 +6,7 @@ package com.wallet.core.primitives.swap import com.wallet.core.primitives.SwapProvider import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName @Serializable data class ApprovalData ( @@ -53,3 +54,15 @@ data class SwapData ( val data: SwapQuoteData ) +@Serializable +enum class SwapStatus(val string: String) { + @SerialName("pending") + Pending("pending"), + @SerialName("completed") + Completed("completed"), + @SerialName("failed") + Failed("failed"), + @SerialName("refunded") + Refunded("refunded"), +} + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4b280fa7d..e58dd5d6b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ reorderable = "3.0.0" mockkVersion = "1.14.5" datastore = "1.1.7" wallet-core = "4.3.5" -gemstone = "0.32.0" +gemstone = "0.33.5" ktor = "3.3.0" appcompat = "1.7.1" material = "1.13.0" diff --git a/ui/src/main/kotlin/com/gemwallet/android/ui/components/image/IconUrlGeneration.kt b/ui/src/main/kotlin/com/gemwallet/android/ui/components/image/IconUrlGeneration.kt index 6bcb28da8..b3fc994db 100644 --- a/ui/src/main/kotlin/com/gemwallet/android/ui/components/image/IconUrlGeneration.kt +++ b/ui/src/main/kotlin/com/gemwallet/android/ui/components/image/IconUrlGeneration.kt @@ -63,7 +63,6 @@ fun SwapperProvider.getSwapProviderIcon(): String { SwapperProvider.PANCAKESWAP_V3, SwapperProvider.PANCAKESWAP_APTOS_V2 -> "pancakeswap" SwapperProvider.THORCHAIN -> "thorchain" - SwapperProvider.ORCA -> "orca" SwapperProvider.JUPITER -> "jupiter" SwapperProvider.ACROSS -> "across" SwapperProvider.OKU -> "oku" diff --git a/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/TransactionItem.kt b/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/TransactionItem.kt index 1b7c7a1e1..e4b687293 100644 --- a/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/TransactionItem.kt +++ b/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/TransactionItem.kt @@ -229,7 +229,11 @@ fun TransactionType.getTitle(direction: TransactionDirection? = null, state: Tra TransactionType.StakeWithdraw -> R.string.transfer_withdraw_title TransactionType.AssetActivation -> R.string.transfer_activate_asset_title TransactionType.TransferNFT -> R.string.transfer_title - TransactionType.SmartContractCall -> TODO() + TransactionType.SmartContractCall -> R.string.transfer_smart_contract_title + TransactionType.PerpetualOpenPosition -> R.string.perpetual_position + TransactionType.PerpetualClosePosition -> R.string.perpetual_close_position + TransactionType.StakeFreeze -> R.string.transfer_freeze_title + TransactionType.StakeUnfreeze -> R.string.transfer_unfreeze_title } } @@ -246,7 +250,11 @@ fun TransactionType.getTransactionTitle(direction: TransactionDirection, state: TransactionType.TokenApproval -> stringResource(id = R.string.transfer_approve_title) TransactionType.AssetActivation -> stringResource(R.string.transfer_activate_asset_title) TransactionType.TransferNFT -> "${stringResource(R.string.transfer_title)} NFT" - TransactionType.SmartContractCall -> TODO() + TransactionType.SmartContractCall -> stringResource(R.string.transfer_smart_contract_title) + TransactionType.PerpetualOpenPosition -> stringResource(R.string.perpetual_position) + TransactionType.PerpetualClosePosition -> stringResource(R.string.perpetual_close_position) + TransactionType.StakeFreeze -> stringResource(R.string.transfer_freeze_title) + TransactionType.StakeUnfreeze -> stringResource(R.string.transfer_unfreeze_title) } } @@ -255,8 +263,10 @@ fun TransactionType.getValue(direction: TransactionDirection, value: String): St TransactionType.StakeUndelegate, TransactionType.StakeRewards, TransactionType.StakeRedelegate, - TransactionType.StakeWithdraw -> value - TransactionType.StakeDelegate -> value + TransactionType.StakeWithdraw, + TransactionType.StakeDelegate, + TransactionType.PerpetualOpenPosition, + TransactionType.PerpetualClosePosition -> value TransactionType.Transfer, TransactionType.Swap -> when (direction) { TransactionDirection.SelfTransfer, @@ -265,8 +275,10 @@ fun TransactionType.getValue(direction: TransactionDirection, value: String): St } TransactionType.TokenApproval, TransactionType.TransferNFT, - TransactionType.AssetActivation -> "" - TransactionType.SmartContractCall -> TODO() + TransactionType.AssetActivation, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, + TransactionType.SmartContractCall -> "" } } @@ -286,8 +298,12 @@ fun TransactionType.getAddress(direction: TransactionDirection, from: String, to TransactionType.StakeRedelegate, TransactionType.StakeWithdraw, TransactionType.AssetActivation, - TransactionType.StakeRewards -> "" - TransactionType.SmartContractCall -> TODO() + TransactionType.StakeRewards, + TransactionType.SmartContractCall, + TransactionType.PerpetualOpenPosition, + TransactionType.StakeFreeze, + TransactionType.StakeUnfreeze, + TransactionType.PerpetualClosePosition -> "" } }