diff --git a/app/src/androidTest/java/one/mixin/android/StringResourceFormatInstrumentedTest.kt b/app/src/androidTest/java/one/mixin/android/StringResourceFormatInstrumentedTest.kt index 2ce28ca11c..118d1fd4b7 100644 --- a/app/src/androidTest/java/one/mixin/android/StringResourceFormatInstrumentedTest.kt +++ b/app/src/androidTest/java/one/mixin/android/StringResourceFormatInstrumentedTest.kt @@ -166,6 +166,7 @@ class StringResourceFormatInstrumentedTest { R.string.Avalanche to "Avalanche", R.string.HyperEVM to "HyperEVM", R.string.XLayer to "X Layer", + R.string.Robinhood to "Robinhood", R.string.Toncoin to "TON", ) diff --git a/app/src/main/java/one/mixin/android/Constants.kt b/app/src/main/java/one/mixin/android/Constants.kt index a05956a2e0..538d37ee93 100644 --- a/app/src/main/java/one/mixin/android/Constants.kt +++ b/app/src/main/java/one/mixin/android/Constants.kt @@ -15,6 +15,7 @@ import one.mixin.android.Constants.ChainId.ETHEREUM_CHAIN_ID import one.mixin.android.Constants.ChainId.LIGHTNING_NETWORK_CHAIN_ID import one.mixin.android.Constants.ChainId.Optimism import one.mixin.android.Constants.ChainId.Polygon +import one.mixin.android.Constants.ChainId.Robinhood import one.mixin.android.Constants.ChainId.XLayer import one.mixin.android.Constants.RouteConfig.ROUTE_BOT_USER_ID import one.mixin.android.net.CustomDns @@ -274,8 +275,8 @@ object Constants { } - val Web3EvmChainIds = listOf(ETHEREUM_CHAIN_ID, Polygon, BinanceSmartChain, Base, Arbitrum, Optimism, Avalanche, ChainId.HyperEVM, XLayer) - val Web3ChainIds = listOf(ETHEREUM_CHAIN_ID, Polygon, BinanceSmartChain, Base, Arbitrum, Optimism, Avalanche, ChainId.HyperEVM, XLayer) + val Web3EvmChainIds = listOf(ETHEREUM_CHAIN_ID, Polygon, BinanceSmartChain, Base, Arbitrum, Optimism, Avalanche, ChainId.HyperEVM, XLayer, Robinhood) + val Web3ChainIds = listOf(ETHEREUM_CHAIN_ID, Polygon, BinanceSmartChain, Base, Arbitrum, Optimism, Avalanche, ChainId.HyperEVM, XLayer, Robinhood) val Web3UtxoChainIds = listOf(BITCOIN_CHAIN_ID, ChainId.PEARL_CHAIN_ID) object ChainId { @@ -309,6 +310,8 @@ object Constants { const val XLayer = "37f5a4d1-905f-3b34-8291-c37438c7dcfc" + const val Robinhood = "b304e03d-d004-3102-875b-8266f8407a1a" + const val TON_CHAIN_ID = "ef660437-d915-4e27-ad3f-632bfb6ba0ee" } @@ -356,7 +359,8 @@ object Constants { ETHEREUM_CHAIN_ID to "Ethereum", Base to "Base", Optimism to "Optimism", - Arbitrum to "Arbitrum" + Arbitrum to "Arbitrum", + Robinhood to "Robinhood", ) val btcAssets = mapOf( diff --git a/app/src/main/java/one/mixin/android/db/web3/vo/Web3TokenItem.kt b/app/src/main/java/one/mixin/android/db/web3/vo/Web3TokenItem.kt index 9e45eb2071..e4c9ddcbc4 100644 --- a/app/src/main/java/one/mixin/android/db/web3/vo/Web3TokenItem.kt +++ b/app/src/main/java/one/mixin/android/db/web3/vo/Web3TokenItem.kt @@ -90,6 +90,7 @@ data class Web3TokenItem( chainId == Constants.ChainId.Polygon -> "Polygon" chainId == Constants.ChainId.BinanceSmartChain -> "BNB Chain" chainId == Constants.ChainId.XLayer -> "X Layer" + chainId == Constants.ChainId.Robinhood -> "Robinhood" chainId == Constants.ChainId.BITCOIN_CHAIN_ID -> "Bitcoin" chainId == Constants.ChainId.PEARL_CHAIN_ID -> "Pearl" chainId == Constants.ChainId.SOLANA_CHAIN_ID -> "Solana" @@ -199,6 +200,7 @@ fun Web3TokenItem.getChainFromName(): Chain { chainId == Constants.ChainId.Avalanche -> Chain.Avalanche chainId == Constants.ChainId.HyperEVM -> Chain.HyperEVM chainId == Constants.ChainId.XLayer -> Chain.XLayer + chainId == Constants.ChainId.Robinhood -> Chain.Robinhood chainId == Constants.ChainId.SOLANA_CHAIN_ID -> Chain.Solana chainId == Constants.ChainId.BITCOIN_CHAIN_ID -> Chain.Bitcoin chainId == Constants.ChainId.PEARL_CHAIN_ID -> Chain.Bitcoin @@ -226,6 +228,7 @@ fun Web3TokenItem.getChainSymbolFromName(): String { chainId == Constants.ChainId.BinanceSmartChain -> "BNB" chainId == Constants.ChainId.Polygon -> "POL" chainId == Constants.ChainId.XLayer -> "OKB" + chainId == Constants.ChainId.Robinhood -> "ETH" chainId == Constants.ChainId.BITCOIN_CHAIN_ID -> "BTC" chainId == Constants.ChainId.PEARL_CHAIN_ID -> "PRL" chainId == Constants.ChainId.SOLANA_CHAIN_ID -> "SOL" @@ -246,6 +249,7 @@ fun Web3TokenItem.isNativeEvmAsset(): Boolean = Constants.ChainId.HyperEVM, Constants.ChainId.BinanceSmartChain, Constants.ChainId.XLayer, + Constants.ChainId.Robinhood, -> assetKey == "0x0000000000000000000000000000000000000000" else -> false } diff --git a/app/src/main/java/one/mixin/android/extension/ContextExtension.kt b/app/src/main/java/one/mixin/android/extension/ContextExtension.kt index 7d2c139470..33444b78e1 100644 --- a/app/src/main/java/one/mixin/android/extension/ContextExtension.kt +++ b/app/src/main/java/one/mixin/android/extension/ContextExtension.kt @@ -1157,6 +1157,7 @@ fun Fragment.getTipsByAsset(asset: TokenItem) = Constants.ChainId.Avalanche, Constants.ChainId.HyperEVM, Constants.ChainId.XLayer, + Constants.ChainId.Robinhood, -> getString(R.string.deposit_tip_chain, asset.symbol, asset.chainName ?: getChainName(asset.chainId, asset.chainName, asset.assetKey ?: "")) else -> getString(R.string.deposit_tip_common, asset.symbol) } diff --git a/app/src/main/java/one/mixin/android/pay/DepositUri.kt b/app/src/main/java/one/mixin/android/pay/DepositUri.kt index b8bfb9b89e..5a8af70f22 100644 --- a/app/src/main/java/one/mixin/android/pay/DepositUri.kt +++ b/app/src/main/java/one/mixin/android/pay/DepositUri.kt @@ -114,6 +114,16 @@ internal fun generateDepositUri( } } + ChainId.Robinhood -> { + if (assetId == ChainId.Robinhood) { + val weiAmount = nativeEvmWeiAmount(cleanAmount) + "ethereum:$address@4663?value=$weiAmount" + } else { + val uint256Amount = erc20Amount(cleanAmount, precision) + "ethereum:${assetKey}@4663/transfer?address=$address&amount=$cleanAmount&uint256=$uint256Amount" + } + } + ChainId.Litecoin -> { "litecoin:$address?amount=$cleanAmount" } diff --git a/app/src/main/java/one/mixin/android/pay/Ethereum.kt b/app/src/main/java/one/mixin/android/pay/Ethereum.kt index af2c564b43..34e616ac0d 100644 --- a/app/src/main/java/one/mixin/android/pay/Ethereum.kt +++ b/app/src/main/java/one/mixin/android/pay/Ethereum.kt @@ -148,5 +148,6 @@ private val ethereumChainIdMap by lazy { 8453 to Constants.ChainId.Base, 42161 to Constants.ChainId.Arbitrum, 999 to Constants.ChainId.HyperEVM, + 4663 to Constants.ChainId.Robinhood, ) } diff --git a/app/src/main/java/one/mixin/android/tip/wc/internal/Chain.kt b/app/src/main/java/one/mixin/android/tip/wc/internal/Chain.kt index 7a6048e618..7114406d4e 100644 --- a/app/src/main/java/one/mixin/android/tip/wc/internal/Chain.kt +++ b/app/src/main/java/one/mixin/android/tip/wc/internal/Chain.kt @@ -36,6 +36,8 @@ sealed class Chain( object XLayer : Chain(Constants.ChainId.XLayer, "eip155", "196", "0xc4", "X Layer", "OKB", listOf("https://rpc.xlayer.tech")) + object Robinhood : Chain(Constants.ChainId.Robinhood, "eip155", "4663", "0x1237", "Robinhood", "ETH", listOf("https://rpc.mainnet.chain.robinhood.com")) + object Solana : Chain( SOLANA_CHAIN_ID, "solana", @@ -76,13 +78,14 @@ sealed class Chain( Avalanche -> Constants.ChainId.Avalanche HyperEVM -> Constants.ChainId.HyperEVM XLayer -> Constants.ChainId.XLayer + Robinhood -> Constants.ChainId.Robinhood Solana -> Constants.ChainId.Solana Bitcoin -> BITCOIN_CHAIN_ID } } // Chain.Blast -internal val supportChainList = listOf(Chain.Solana, Chain.Bitcoin, Chain.Ethereum, Chain.Base, Chain.BinanceSmartChain, Chain.Polygon, Chain.Optimism, Chain.Arbitrum, Chain.Avalanche, Chain.HyperEVM, Chain.XLayer) -internal val evmChainList = listOf(Chain.Ethereum, Chain.Base, Chain.BinanceSmartChain, Chain.Polygon, Chain.Optimism, Chain.Arbitrum, Chain.Avalanche, Chain.HyperEVM, Chain.XLayer) +internal val supportChainList = listOf(Chain.Solana, Chain.Bitcoin, Chain.Ethereum, Chain.Base, Chain.BinanceSmartChain, Chain.Polygon, Chain.Optimism, Chain.Arbitrum, Chain.Avalanche, Chain.HyperEVM, Chain.XLayer, Chain.Robinhood) +internal val evmChainList = listOf(Chain.Ethereum, Chain.Base, Chain.BinanceSmartChain, Chain.Polygon, Chain.Optimism, Chain.Arbitrum, Chain.Avalanche, Chain.HyperEVM, Chain.XLayer, Chain.Robinhood) data class WalletConnectAddresses( val evm: String, diff --git a/app/src/main/java/one/mixin/android/ui/wallet/DepositFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/DepositFragment.kt index bf2a7ac057..6ceafeb2a0 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/DepositFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/DepositFragment.kt @@ -349,6 +349,7 @@ class DepositFragment : BaseFragment() { Constants.ChainId.Avalanche, Constants.ChainId.HyperEVM, Constants.ChainId.XLayer, + Constants.ChainId.Robinhood, Constants.ChainId.TON_CHAIN_ID -> true else -> false diff --git a/app/src/main/java/one/mixin/android/ui/wallet/TokenListBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/TokenListBottomSheetDialogFragment.kt index 6b124c908a..d8d9608fb9 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/TokenListBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/TokenListBottomSheetDialogFragment.kt @@ -26,6 +26,7 @@ import one.mixin.android.Constants.ChainId.ETHEREUM_CHAIN_ID import one.mixin.android.Constants.ChainId.HyperEVM import one.mixin.android.Constants.ChainId.Optimism import one.mixin.android.Constants.ChainId.Polygon +import one.mixin.android.Constants.ChainId.Robinhood import one.mixin.android.Constants.ChainId.SOLANA_CHAIN_ID import one.mixin.android.Constants.ChainId.TON_CHAIN_ID import one.mixin.android.Constants.ChainId.TRON_CHAIN_ID @@ -203,6 +204,10 @@ class TokenListBottomSheetDialogFragment : MixinBottomSheetDialogFragment() { XLayer } + R.id.radio_robinhood -> { + Robinhood + } + else -> { null } diff --git a/app/src/main/java/one/mixin/android/ui/wallet/components/ImportWalletDetailPage.kt b/app/src/main/java/one/mixin/android/ui/wallet/components/ImportWalletDetailPage.kt index 9e3c1f3447..39ab6f2229 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/components/ImportWalletDetailPage.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/components/ImportWalletDetailPage.kt @@ -102,6 +102,7 @@ fun ImportWalletDetailPage( "Avalanche" to Constants.ChainId.Avalanche, "HyperEVM" to Constants.ChainId.HyperEVM, "X Layer" to Constants.ChainId.XLayer, + "Robinhood" to Constants.ChainId.Robinhood, "Solana" to Constants.ChainId.SOLANA_CHAIN_ID ) var expanded by remember { mutableStateOf(false) } @@ -127,7 +128,7 @@ fun ImportWalletDetailPage( val isEvmNetwork = when (selectedNetworkName) { - "Ethereum", "Base", "BSC", "Polygon", "Arbitrum", "Optimism", "Avalanche", "HyperEVM", "X Layer" -> true + "Ethereum", "Base", "BSC", "Polygon", "Arbitrum", "Optimism", "Avalanche", "HyperEVM", "X Layer", "Robinhood" -> true else -> false } val isBitcoin: Boolean = selectedNetworkName == "Bitcoin" diff --git a/app/src/main/java/one/mixin/android/util/ChainNetwork.kt b/app/src/main/java/one/mixin/android/util/ChainNetwork.kt index 448af4b977..f714d8eadb 100644 --- a/app/src/main/java/one/mixin/android/util/ChainNetwork.kt +++ b/app/src/main/java/one/mixin/android/util/ChainNetwork.kt @@ -18,6 +18,7 @@ private val chainNetworks by lazy { Constants.ChainId.Arbitrum to "Arbitrum", Constants.ChainId.HyperEVM to "HyperEVM", Constants.ChainId.XLayer to "X Layer", + Constants.ChainId.Robinhood to "Robinhood", ) } @@ -45,6 +46,8 @@ fun getChainNetwork( return "Optimism" } else if (chainId == Constants.ChainId.XLayer) { return "X Layer" + } else if (chainId == Constants.ChainId.Robinhood) { + return "Robinhood" } if (assetId == chainId && !bepChains.contains(chainId) && assetId != Constants.ChainId.LIGHTNING_NETWORK_CHAIN_ID) return null @@ -68,6 +71,7 @@ private val chainNames by lazy { Constants.ChainId.BinanceSmartChain to "BNB Smart Chain (BEP-20)", Constants.ChainId.LIGHTNING_NETWORK_CHAIN_ID to "Lightning", Constants.ChainId.XLayer to "X Layer", + Constants.ChainId.Robinhood to "Robinhood", ) } diff --git a/app/src/main/java/one/mixin/android/web3/Web3ChainId.kt b/app/src/main/java/one/mixin/android/web3/Web3ChainId.kt index f762c2e9bd..db011da852 100644 --- a/app/src/main/java/one/mixin/android/web3/Web3ChainId.kt +++ b/app/src/main/java/one/mixin/android/web3/Web3ChainId.kt @@ -20,8 +20,9 @@ object Web3ChainId { const val AvalancheChainId = 43114 const val BlastChainId = 81457 const val HyperEvmChainId = 999 + const val RobinhoodChainId = 4663 - val eip155ChainIds = listOf(EthChainId, OptimismChainId, BscChainId, PolygonChainId, XLayerChainId, BaseChainId, ArbitrumChainId, AvalancheChainId, BlastChainId, HyperEvmChainId) + val eip155ChainIds = listOf(EthChainId, OptimismChainId, BscChainId, PolygonChainId, XLayerChainId, BaseChainId, ArbitrumChainId, AvalancheChainId, BlastChainId, HyperEvmChainId, RobinhoodChainId) fun getChainType(id: Int): ChainType = when { @@ -41,6 +42,7 @@ object Web3ChainId { ArbitrumChainId -> Chain.Arbitrum AvalancheChainId -> Chain.Avalanche HyperEvmChainId -> Chain.HyperEVM + RobinhoodChainId -> Chain.Robinhood else -> Chain.Solana } } diff --git a/app/src/main/java/one/mixin/android/web3/js/Web3Signer.kt b/app/src/main/java/one/mixin/android/web3/js/Web3Signer.kt index 1cb569eb82..9ad94a2f9c 100644 --- a/app/src/main/java/one/mixin/android/web3/js/Web3Signer.kt +++ b/app/src/main/java/one/mixin/android/web3/js/Web3Signer.kt @@ -68,6 +68,7 @@ internal fun findChainByHexReference(hex: String?): Chain? = Chain.BinanceSmartChain, Chain.HyperEVM, Chain.XLayer, + Chain.Robinhood, Chain.Solana, ).firstOrNull { it.hexReference == hex } @@ -316,6 +317,11 @@ object Web3Signer { persist() Result.success(Chain.XLayer.name) } + Chain.Robinhood.hexReference -> { + currentChain = Chain.Robinhood + persist() + Result.success(Chain.Robinhood.name) + } Chain.Solana.hexReference -> { currentChain = Chain.Solana currentNetwork = JsSignerNetwork.Solana.name diff --git a/app/src/main/java/one/mixin/android/web3/receive/Web3TokenListBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/web3/receive/Web3TokenListBottomSheetDialogFragment.kt index fbd1f3c7ba..dba798b559 100644 --- a/app/src/main/java/one/mixin/android/web3/receive/Web3TokenListBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/web3/receive/Web3TokenListBottomSheetDialogFragment.kt @@ -29,6 +29,7 @@ import one.mixin.android.Constants.ChainId.BinanceSmartChain import one.mixin.android.Constants.ChainId.ETHEREUM_CHAIN_ID import one.mixin.android.Constants.ChainId.Optimism import one.mixin.android.Constants.ChainId.Polygon +import one.mixin.android.Constants.ChainId.Robinhood import one.mixin.android.Constants.ChainId.SOLANA_CHAIN_ID import one.mixin.android.Constants.ChainId.TON_CHAIN_ID import one.mixin.android.Constants.ChainId.XLayer @@ -170,6 +171,10 @@ class Web3TokenListBottomSheetDialogFragment : MixinBottomSheetDialogFragment() XLayer } + R.id.radio_robinhood -> { + Robinhood + } + else -> { null } diff --git a/app/src/main/java/one/mixin/android/web3/swap/SwapTokenListBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/web3/swap/SwapTokenListBottomSheetDialogFragment.kt index 1da43d6910..da36c4c74d 100644 --- a/app/src/main/java/one/mixin/android/web3/swap/SwapTokenListBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/web3/swap/SwapTokenListBottomSheetDialogFragment.kt @@ -31,6 +31,7 @@ import one.mixin.android.Constants.ChainId.BinanceSmartChain import one.mixin.android.Constants.ChainId.ETHEREUM_CHAIN_ID import one.mixin.android.Constants.ChainId.Optimism import one.mixin.android.Constants.ChainId.Polygon +import one.mixin.android.Constants.ChainId.Robinhood import one.mixin.android.Constants.ChainId.SOLANA_CHAIN_ID import one.mixin.android.Constants.ChainId.TON_CHAIN_ID import one.mixin.android.Constants.ChainId.XLayer @@ -227,6 +228,10 @@ class SwapTokenListBottomSheetDialogFragment : MixinBottomSheetDialogFragment() XLayer } + R.id.radio_robinhood -> { + Robinhood + } + R.id.radio_toncoin -> { TON_CHAIN_ID } diff --git a/app/src/main/res/layout/fragment_asset_list_bottom_sheet.xml b/app/src/main/res/layout/fragment_asset_list_bottom_sheet.xml index 4ef4cc4fcd..20fbceca3e 100644 --- a/app/src/main/res/layout/fragment_asset_list_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_asset_list_bottom_sheet.xml @@ -260,6 +260,17 @@ android:text="@string/XLayer" android:textSize="14sp" android:textColor="@drawable/radio_button_text_selector" /> + + @@ -339,4 +350,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fea21e623b..2a41529d8b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1585,6 +1585,7 @@ Avalanche HyperEVM X Layer + Robinhood TON %1$s Account Account diff --git a/app/src/test/java/one/mixin/android/RobinhoodChainClassificationTest.kt b/app/src/test/java/one/mixin/android/RobinhoodChainClassificationTest.kt new file mode 100644 index 0000000000..594e1c856e --- /dev/null +++ b/app/src/test/java/one/mixin/android/RobinhoodChainClassificationTest.kt @@ -0,0 +1,17 @@ +package one.mixin.android + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class RobinhoodChainClassificationTest { + @Test + fun robinhoodUsesExpectedMixinChainIdAndEvmClassification() { + assertEquals("b304e03d-d004-3102-875b-8266f8407a1a", Constants.ChainId.Robinhood) + assertTrue(Constants.ChainId.Robinhood in Constants.Web3EvmChainIds) + assertTrue(Constants.ChainId.Robinhood in Constants.Web3ChainIds) + assertFalse(Constants.ChainId.Robinhood in Constants.Web3UtxoChainIds) + assertEquals("Robinhood", Constants.AssetId.ethAssets[Constants.ChainId.Robinhood]) + } +} diff --git a/app/src/test/java/one/mixin/android/compose/RobinhoodDepositUriTest.kt b/app/src/test/java/one/mixin/android/compose/RobinhoodDepositUriTest.kt new file mode 100644 index 0000000000..7b8f9904d8 --- /dev/null +++ b/app/src/test/java/one/mixin/android/compose/RobinhoodDepositUriTest.kt @@ -0,0 +1,38 @@ +package one.mixin.android.compose + +import one.mixin.android.Constants +import one.mixin.android.pay.generateDepositUri +import org.junit.Assert.assertEquals +import org.junit.Test + +class RobinhoodDepositUriTest { + @Test + fun nativeEthDepositUriUsesRobinhoodChainId() { + assertEquals( + "ethereum:0x1111111111111111111111111111111111111111@4663?value=1500000000000000000", + generateDepositUri( + assetId = Constants.ChainId.Robinhood, + chainId = Constants.ChainId.Robinhood, + assetKey = "0x0000000000000000000000000000000000000000", + address = "0x1111111111111111111111111111111111111111", + amount = "1.5", + precision = 18, + ), + ) + } + + @Test + fun robinhoodErc20DepositUriUsesTransferCall() { + assertEquals( + "ethereum:0x2222222222222222222222222222222222222222@4663/transfer?address=0x1111111111111111111111111111111111111111&amount=1.5&uint256=1500000", + generateDepositUri( + assetId = "token", + chainId = Constants.ChainId.Robinhood, + assetKey = "0x2222222222222222222222222222222222222222", + address = "0x1111111111111111111111111111111111111111", + amount = "1.5", + precision = 6, + ), + ) + } +} diff --git a/app/src/test/java/one/mixin/android/db/web3/vo/RobinhoodTokenItemTest.kt b/app/src/test/java/one/mixin/android/db/web3/vo/RobinhoodTokenItemTest.kt new file mode 100644 index 0000000000..3fa80302fe --- /dev/null +++ b/app/src/test/java/one/mixin/android/db/web3/vo/RobinhoodTokenItemTest.kt @@ -0,0 +1,52 @@ +package one.mixin.android.db.web3.vo + +import one.mixin.android.Constants +import one.mixin.android.crypto.CryptoWalletHelper +import one.mixin.android.tip.wc.internal.Chain +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class RobinhoodTokenItemTest { + @Test + fun robinhoodTokenUsesExpectedDisplayAndNativeAssetMetadata() { + val nativeToken = token("0x0000000000000000000000000000000000000000") + val erc20Token = token("0x1111111111111111111111111111111111111111") + + assertEquals("Robinhood", nativeToken.getChainDisplayName()) + assertEquals("ETH", nativeToken.getChainSymbolFromName()) + assertEquals(Chain.Robinhood, nativeToken.getChainFromName()) + assertTrue(nativeToken.isNativeEvmAsset()) + assertFalse(erc20Token.isNativeEvmAsset()) + } + + @Test + fun robinhoodReusesEthereumAddressDerivation() { + val privateKey = "0000000000000000000000000000000000000000000000000000000000000001" + + assertEquals( + CryptoWalletHelper.privateKeyToAddress(privateKey, Constants.ChainId.ETHEREUM_CHAIN_ID), + CryptoWalletHelper.privateKeyToAddress(privateKey, Constants.ChainId.Robinhood), + ) + } + + private fun token(assetKey: String) = Web3TokenItem( + walletId = "wallet", + assetId = Constants.ChainId.Robinhood, + chainId = Constants.ChainId.Robinhood, + name = "ETH", + assetKey = assetKey, + symbol = "ETH", + iconUrl = "", + precision = 18, + balance = "0", + priceUsd = "0", + changeUsd = "0", + chainIcon = null, + chainName = null, + chainSymbol = null, + hidden = false, + level = 1, + ) +} diff --git a/app/src/test/java/one/mixin/android/pay/RobinhoodEthereumUriTest.kt b/app/src/test/java/one/mixin/android/pay/RobinhoodEthereumUriTest.kt new file mode 100644 index 0000000000..82705b8b77 --- /dev/null +++ b/app/src/test/java/one/mixin/android/pay/RobinhoodEthereumUriTest.kt @@ -0,0 +1,32 @@ +package one.mixin.android.pay + +import kotlinx.coroutines.runBlocking +import one.mixin.android.Constants +import one.mixin.android.api.response.AddressResponse +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Test + +class RobinhoodEthereumUriTest { + @Test + fun erc681ChainIdResolvesToRobinhood() = runBlocking { + val destination = "0x1111111111111111111111111111111111111111" + var validatedChainId: String? = null + + val transfer = parseEthereum( + url = "ethereum:$destination@4663", + validateAddress = { assetId, chainId, address -> + validatedChainId = chainId + AddressResponse(address, assetId = assetId) + }, + getFee = { _, _ -> emptyList() }, + findAssetIdByAssetKey = { null }, + getAssetPrecisionById = { null }, + balanceCheck = { _, _, _, _ -> }, + ) + + assertNotNull(transfer) + assertEquals(Constants.ChainId.Robinhood, validatedChainId) + assertEquals(Constants.ChainId.Robinhood, transfer?.assetId) + } +} diff --git a/app/src/test/java/one/mixin/android/tip/wc/internal/RobinhoodWalletConnectTest.kt b/app/src/test/java/one/mixin/android/tip/wc/internal/RobinhoodWalletConnectTest.kt new file mode 100644 index 0000000000..3e368d6b5c --- /dev/null +++ b/app/src/test/java/one/mixin/android/tip/wc/internal/RobinhoodWalletConnectTest.kt @@ -0,0 +1,20 @@ +package one.mixin.android.tip.wc.internal + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class RobinhoodWalletConnectTest { + @Test + fun robinhoodUsesExpectedWalletConnectMetadata() { + assertEquals("b304e03d-d004-3102-875b-8266f8407a1a", Chain.Robinhood.assetId) + assertEquals("eip155:4663", Chain.Robinhood.chainId) + assertEquals("0x1237", Chain.Robinhood.hexReference) + assertEquals("Robinhood", Chain.Robinhood.name) + assertEquals("ETH", Chain.Robinhood.symbol) + assertEquals(Chain.Robinhood.assetId, Chain.Robinhood.getWeb3ChainId()) + assertEquals(Chain.Robinhood, getChainByChainId("eip155:4663")) + assertEquals(Chain.Robinhood, "4663".getChain()) + assertTrue(Chain.Robinhood in evmChainList) + } +} diff --git a/app/src/test/java/one/mixin/android/util/RobinhoodChainNetworkTest.kt b/app/src/test/java/one/mixin/android/util/RobinhoodChainNetworkTest.kt new file mode 100644 index 0000000000..d2259f89ff --- /dev/null +++ b/app/src/test/java/one/mixin/android/util/RobinhoodChainNetworkTest.kt @@ -0,0 +1,13 @@ +package one.mixin.android.util + +import one.mixin.android.Constants +import org.junit.Assert.assertEquals +import org.junit.Test + +class RobinhoodChainNetworkTest { + @Test + fun robinhoodFallbacksUseDisplayName() { + assertEquals("Robinhood", getChainNetwork("token", Constants.ChainId.Robinhood, "asset-key")) + assertEquals("Robinhood", getChainName(Constants.ChainId.Robinhood, null, "asset-key")) + } +} diff --git a/app/src/test/java/one/mixin/android/web3/RobinhoodChainIdTest.kt b/app/src/test/java/one/mixin/android/web3/RobinhoodChainIdTest.kt new file mode 100644 index 0000000000..30eeb4b7a4 --- /dev/null +++ b/app/src/test/java/one/mixin/android/web3/RobinhoodChainIdTest.kt @@ -0,0 +1,16 @@ +package one.mixin.android.web3 + +import one.mixin.android.tip.wc.internal.Chain +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class RobinhoodChainIdTest { + @Test + fun numericChainIdResolvesToRobinhoodEvm() { + assertEquals(4663, Web3ChainId.RobinhoodChainId) + assertTrue(Web3ChainId.RobinhoodChainId in Web3ChainId.eip155ChainIds) + assertEquals(ChainType.ethereum, Web3ChainId.getChainType(Web3ChainId.RobinhoodChainId)) + assertEquals(Chain.Robinhood, Web3ChainId.getChain(Web3ChainId.RobinhoodChainId)) + } +} diff --git a/app/src/test/java/one/mixin/android/web3/js/RobinhoodSignerNetworkTest.kt b/app/src/test/java/one/mixin/android/web3/js/RobinhoodSignerNetworkTest.kt new file mode 100644 index 0000000000..469ed101f6 --- /dev/null +++ b/app/src/test/java/one/mixin/android/web3/js/RobinhoodSignerNetworkTest.kt @@ -0,0 +1,12 @@ +package one.mixin.android.web3.js + +import one.mixin.android.tip.wc.internal.Chain +import org.junit.Assert.assertEquals +import org.junit.Test + +class RobinhoodSignerNetworkTest { + @Test + fun robinhoodHexReferenceResolvesForPersistedChainState() { + assertEquals(Chain.Robinhood, findChainByHexReference("0x1237")) + } +}