Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class StringResourceFormatInstrumentedTest {
R.string.Arbitrum to "Arbitrum",
R.string.Avalanche to "Avalanche",
R.string.HyperEVM to "HyperEVM",
R.string.XLayer to "X Layer",
R.string.Toncoin to "TON",
)

Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/one/mixin/android/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.XLayer
import one.mixin.android.Constants.RouteConfig.ROUTE_BOT_USER_ID
import one.mixin.android.net.CustomDns
import one.mixin.android.net.SequentialDns
Expand Down Expand Up @@ -270,8 +271,8 @@ object Constants {
}


val Web3EvmChainIds = listOf(ETHEREUM_CHAIN_ID, Polygon, BinanceSmartChain, Base, Arbitrum, Optimism, Avalanche, ChainId.HyperEVM)
val Web3ChainIds = listOf(ETHEREUM_CHAIN_ID, Polygon, BinanceSmartChain, Base, Arbitrum, Optimism, Avalanche, ChainId.HyperEVM)
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 Web3UtxoChainIds = listOf(BITCOIN_CHAIN_ID, ChainId.PEARL_CHAIN_ID)

object ChainId {
Expand Down Expand Up @@ -303,6 +304,8 @@ object Constants {

const val HyperEVM = "36d23d9e-bf4e-3ede-a12d-26f1f1f9fd2f"

const val XLayer = "37f5a4d1-905f-3b34-8291-c37438c7dcfc"

const val TON_CHAIN_ID = "ef660437-d915-4e27-ad3f-632bfb6ba0ee"
}

Expand Down
31 changes: 21 additions & 10 deletions app/src/main/java/one/mixin/android/db/web3/vo/Web3TokenItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ data class Web3TokenItem(
chainId == Constants.ChainId.Optimism -> "Optimism"
chainId == Constants.ChainId.Polygon -> "Polygon"
chainId == Constants.ChainId.BinanceSmartChain -> "BNB Chain"
chainId == Constants.ChainId.XLayer -> "X Layer"
chainId == Constants.ChainId.BITCOIN_CHAIN_ID -> "Bitcoin"
chainId == Constants.ChainId.PEARL_CHAIN_ID -> "Pearl"
chainId == Constants.ChainId.SOLANA_CHAIN_ID -> "Solana"
Expand Down Expand Up @@ -197,6 +198,7 @@ fun Web3TokenItem.getChainFromName(): Chain {
chainId == Constants.ChainId.BinanceSmartChain-> Chain.BinanceSmartChain
chainId == Constants.ChainId.Avalanche -> Chain.Avalanche
chainId == Constants.ChainId.HyperEVM -> Chain.HyperEVM
chainId == Constants.ChainId.XLayer -> Chain.XLayer
chainId == Constants.ChainId.SOLANA_CHAIN_ID -> Chain.Solana
chainId == Constants.ChainId.BITCOIN_CHAIN_ID -> Chain.Bitcoin
chainId == Constants.ChainId.PEARL_CHAIN_ID -> Chain.Bitcoin
Expand All @@ -223,13 +225,31 @@ fun Web3TokenItem.getChainSymbolFromName(): String {
chainId == Constants.ChainId.HyperEVM -> "HYPE"
chainId == Constants.ChainId.BinanceSmartChain -> "BNB"
chainId == Constants.ChainId.Polygon -> "POL"
chainId == Constants.ChainId.XLayer -> "OKB"
chainId == Constants.ChainId.BITCOIN_CHAIN_ID -> "BTC"
chainId == Constants.ChainId.PEARL_CHAIN_ID -> "PRL"
chainId == Constants.ChainId.SOLANA_CHAIN_ID -> "SOL"
else -> throw IllegalArgumentException("Not support: $chainId")
}
}

fun Web3TokenItem.isNativeEvmAsset(): Boolean =
when (chainId) {
Constants.ChainId.Polygon ->
assetKey == "0x0000000000000000000000000000000000000000" ||
assetKey == "0x0000000000000000000000000000000000001010"
Constants.ChainId.ETHEREUM_CHAIN_ID,
Constants.ChainId.Base,
Constants.ChainId.Optimism,
Constants.ChainId.Arbitrum,
Constants.ChainId.Avalanche,
Constants.ChainId.HyperEVM,
Constants.ChainId.BinanceSmartChain,
Constants.ChainId.XLayer,
-> assetKey == "0x0000000000000000000000000000000000000000"
else -> false
}


suspend fun Web3TokenItem.buildTransaction(
rpc: Rpc,
Expand Down Expand Up @@ -315,17 +335,8 @@ suspend fun Web3TokenItem.buildTransaction(
return JsSignMessage(0, JsSignMessage.TYPE_RAW_TRANSACTION, data = tx, solanaTxSource = SolanaTxSource.InnerTransfer)
} else if (chainId in Constants.Web3EvmChainIds) {
Web3Signer.useEvm()
// (chainId.equals("blast", true) && assetKey == "0x0000000000000000000000000000000000000000") ||
val transaction =
if ((chainId == Constants.ChainId.Base && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainId == Constants.ChainId.ETHEREUM_CHAIN_ID && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainId == Constants.ChainId.Polygon && (assetKey == "0x0000000000000000000000000000000000000000" || assetKey == "0x0000000000000000000000000000000000001010")) ||
(chainId == Constants.ChainId.BinanceSmartChain && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainId == Constants.ChainId.Optimism && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainId == Constants.ChainId.Arbitrum && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainId == Constants.ChainId.Avalanche && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainId == Constants.ChainId.HyperEVM && assetKey == "0x0000000000000000000000000000000000000000")
) {
if (isNativeEvmAsset()) {
val value = Numeric.toHexStringWithPrefix(Convert.toWei(v, Convert.Unit.ETHER).toBigInteger())
WCEthereumTransaction(fromAddress, toAddress, null, null, null, null, null, null, value, null)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,14 @@ data class Web3TransactionItem(

fun isNotVerified() = level < Constants.AssetLevel.VERIFIED

fun displayFeeAmount(): String = sponsorFeeAmount?.ifBlank { fee } ?: fee
fun displayFeeAmount(): String = if (hasSponsorFee()) sponsorFeeAmount.orEmpty() else fee

fun displayFeeSymbol(): String? = sponsorFeeAssetSymbol ?: chainSymbol
fun displayFeeSymbol(): String? = if (hasSponsorFee()) sponsorFeeAssetSymbol ?: chainSymbol else chainSymbol

fun hasSponsorFee(): Boolean = !sponsorFeeAmount.isNullOrBlank()
fun hasSponsorFee(): Boolean {
val amount = sponsorFeeAmount?.takeIf { it.isNotBlank() } ?: return false
return amount.toBigDecimalOrNull()?.signum()?.let { it != 0 } ?: true
}

fun getMainAmount(): String {
return when (transactionType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,8 @@ fun Fragment.getTipsByAsset(asset: TokenItem) =
Constants.ChainId.Polygon,
Constants.ChainId.BitShares,
Constants.ChainId.Avalanche,
Constants.ChainId.HyperEVM
Constants.ChainId.HyperEVM,
Constants.ChainId.XLayer,
-> 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)
}
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/one/mixin/android/pay/DepositUri.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ internal fun generateDepositUri(
}
}

ChainId.XLayer -> {
if (assetId == ChainId.XLayer) {
val weiAmount = nativeEvmWeiAmount(cleanAmount)
"ethereum:$address@196?value=$weiAmount"
} else {
val uint256Amount = erc20Amount(cleanAmount, precision)
"ethereum:${assetKey}@196/transfer?address=$address&amount=$cleanAmount&uint256=$uint256Amount"
}
}

ChainId.Litecoin -> {
"litecoin:$address?amount=$cleanAmount"
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/one/mixin/android/pay/Ethereum.kt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ private val ethereumChainIdMap by lazy {
10 to Constants.ChainId.Optimism,
56 to Constants.ChainId.BinanceSmartChain,
137 to Constants.ChainId.Polygon,
196 to Constants.ChainId.XLayer,
8453 to Constants.ChainId.Base,
42161 to Constants.ChainId.Arbitrum,
999 to Constants.ChainId.HyperEVM,
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/one/mixin/android/tip/wc/internal/Chain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ sealed class Chain(

object HyperEVM : Chain(Constants.ChainId.HyperEVM, "eip155", "999", "0x3e7", "HyperEVM", "HYPE", listOf("https://rpc.hyperliquid.xyz/evm"))

object XLayer : Chain(Constants.ChainId.XLayer, "eip155", "196", "0xc4", "X Layer", "OKB", listOf("https://rpc.xlayer.tech"))

object Solana : Chain(
SOLANA_CHAIN_ID,
"solana",
Expand Down Expand Up @@ -73,13 +75,14 @@ sealed class Chain(
Base -> Constants.ChainId.Base
Avalanche -> Constants.ChainId.Avalanche
HyperEVM -> Constants.ChainId.HyperEVM
XLayer -> Constants.ChainId.XLayer
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)
internal val evmChainList = listOf(Chain.Ethereum, Chain.Base, Chain.BinanceSmartChain, Chain.Polygon, Chain.Optimism, Chain.Arbitrum, Chain.Avalanche, Chain.HyperEVM)
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)

data class WalletConnectAddresses(
val evm: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ import one.mixin.android.web3.receive.Web3AddressFragment
import one.mixin.android.web3.requiredSolBalance
import one.mixin.android.web3.solanaRecipientAccountState
import one.mixin.android.web3.swap.SwapTokenListBottomSheetDialogFragment
import one.mixin.android.web3.swap.filterSwapTokensByWalletChains
import timber.log.Timber
import java.math.BigDecimal
import javax.inject.Inject
Expand Down Expand Up @@ -1494,13 +1495,8 @@ class TradeFragment : BaseFragment() {
return@requestRouteAPI true
},
)?.let { remote: List<SwapToken> ->
val filteredRemote: List<SwapToken> = (if (chainIdSet == null) {
remote
} else {
remote.filter { token: SwapToken ->
chainIdSet.contains(token.chain.chainId)
}
}).filter { inMixin() || isWeb3TransferSupported(it.chain.chainId) }
val filteredRemote: List<SwapToken> =
filterSwapTokensByWalletChains(remote, chainIdSet, inMixin())
stocks = filteredRemote.map { it.copy(isWeb3 = !inMixin(), walletId = walletId) }.map { token ->
val t = web3tokens?.firstOrNull { web3Token ->
(web3Token.assetKey == token.address && web3Token.assetId == token.assetId)
Expand Down Expand Up @@ -1531,13 +1527,8 @@ class TradeFragment : BaseFragment() {
return@requestRouteAPI true
},
)?.let { remote: List<SwapToken> ->
val filteredRemote: List<SwapToken> = (if (chainIdSet == null) {
remote
} else {
remote.filter { token: SwapToken ->
chainIdSet.contains(token.chain.chainId)
}
}).filter { inMixin() || isWeb3TransferSupported(it.chain.chainId) }
val filteredRemote: List<SwapToken> =
filterSwapTokensByWalletChains(remote, chainIdSet, inMixin())
if (!inMixin()) {
remoteSwapTokens = filteredRemote.map { it.copy(isWeb3 = true, walletId = walletId) }.mapNotNull { token ->
val local = swapViewModel.web3TokenItemById(walletId ?: "", token.assetId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ class DepositFragment : BaseFragment() {
Constants.ChainId.LIGHTNING_NETWORK_CHAIN_ID,
Constants.ChainId.Avalanche,
Constants.ChainId.HyperEVM,
Constants.ChainId.XLayer,
Constants.ChainId.TON_CHAIN_ID -> true

else -> false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import one.mixin.android.Constants.ChainId.Polygon
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
import one.mixin.android.Constants.ChainId.XLayer
import one.mixin.android.R
import one.mixin.android.databinding.FragmentAssetListBottomSheetBinding
import one.mixin.android.extension.addToList
Expand Down Expand Up @@ -198,6 +199,10 @@ class TokenListBottomSheetDialogFragment : MixinBottomSheetDialogFragment() {
HyperEVM
}

R.id.radio_xlayer -> {
XLayer
}

else -> {
null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ fun ImportWalletDetailPage(
"Optimism" to Constants.ChainId.Optimism,
"Avalanche" to Constants.ChainId.Avalanche,
"HyperEVM" to Constants.ChainId.HyperEVM,
"X Layer" to Constants.ChainId.XLayer,
"Solana" to Constants.ChainId.SOLANA_CHAIN_ID
)
var expanded by remember { mutableStateOf(false) }
Expand All @@ -126,7 +127,7 @@ fun ImportWalletDetailPage(


val isEvmNetwork = when (selectedNetworkName) {
"Ethereum", "Base", "BSC", "Polygon", "Arbitrum", "Optimism", "Avalanche", "HyperEVM" -> true
"Ethereum", "Base", "BSC", "Polygon", "Arbitrum", "Optimism", "Avalanche", "HyperEVM", "X Layer" -> true
else -> false
}
val isBitcoin: Boolean = selectedNetworkName == "Bitcoin"
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/one/mixin/android/util/ChainNetwork.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ private val chainNetworks by lazy {
Constants.ChainId.Optimism to "Optimism",
Constants.ChainId.Arbitrum to "Arbitrum",
Constants.ChainId.HyperEVM to "HyperEVM",
Constants.ChainId.XLayer to "X Layer",
)
}

Expand All @@ -42,6 +43,8 @@ fun getChainNetwork(
return "Arbitrum"
} else if (chainId == Constants.ChainId.Optimism) {
return "Optimism"
} else if (chainId == Constants.ChainId.XLayer) {
return "X Layer"
}

if (assetId == chainId && !bepChains.contains(chainId) && assetId != Constants.ChainId.LIGHTNING_NETWORK_CHAIN_ID) return null
Expand All @@ -64,6 +67,7 @@ private val chainNames by lazy {
Constants.ChainId.BitShares to "BitShares",
Constants.ChainId.BinanceSmartChain to "BNB Smart Chain (BEP-20)",
Constants.ChainId.LIGHTNING_NETWORK_CHAIN_ID to "Lightning",
Constants.ChainId.XLayer to "X Layer",
)
}

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/one/mixin/android/web3/Web3ChainId.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ object Web3ChainId {
const val OptimismChainId = 10
const val BscChainId = 56
const val PolygonChainId = 137
const val XLayerChainId = 196
const val BaseChainId = 8453
const val ArbitrumChainId = 42161
const val AvalancheChainId = 43114
const val BlastChainId = 81457
const val HyperEvmChainId = 999

val eip155ChainIds = listOf(EthChainId, OptimismChainId, BscChainId, PolygonChainId, BaseChainId, ArbitrumChainId, AvalancheChainId, BlastChainId, HyperEvmChainId)
val eip155ChainIds = listOf(EthChainId, OptimismChainId, BscChainId, PolygonChainId, XLayerChainId, BaseChainId, ArbitrumChainId, AvalancheChainId, BlastChainId, HyperEvmChainId)

fun getChainType(id: Int): ChainType =
when {
Expand All @@ -35,6 +36,7 @@ object Web3ChainId {
OptimismChainId -> Chain.Optimism
BscChainId -> Chain.BinanceSmartChain
PolygonChainId -> Chain.Polygon
XLayerChainId -> Chain.XLayer
BaseChainId -> Chain.Base
ArbitrumChainId -> Chain.Arbitrum
AvalancheChainId -> Chain.Avalanche
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package one.mixin.android.web3.details

import one.mixin.android.db.web3.vo.TransactionStatus
import one.mixin.android.db.web3.vo.TransactionType

internal data class Web3TransactionDetailState(
val status: String,
val transactionType: String,
) {
val amountTone: Web3TransactionAmountTone
get() = when {
status == TransactionStatus.PENDING.value ||
status == TransactionStatus.NOT_FOUND.value ||
status == TransactionStatus.FAILED.value -> Web3TransactionAmountTone.ASSIST
transactionType == TransactionType.TRANSFER_OUT.value -> Web3TransactionAmountTone.OUTGOING
transactionType == TransactionType.TRANSFER_IN.value -> Web3TransactionAmountTone.INCOMING
else -> Web3TransactionAmountTone.PRIMARY
}

fun withStatus(status: String): Web3TransactionDetailState = copy(status = status)
}

internal enum class Web3TransactionAmountTone {
ASSIST,
OUTGOING,
INCOMING,
PRIMARY,
}
Loading