Skip to content
Open
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
13 changes: 11 additions & 2 deletions app/src/main/java/one/mixin/android/compose/theme/Theme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.colorspace.ColorSpaces
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import one.mixin.android.MixinApplication
import one.mixin.android.extension.isNightMode
import one.mixin.android.extension.isScreenWideColorGamut
import one.mixin.android.util.isCurrChinese

val isP3Supported = MixinApplication.appContext.isScreenWideColorGamut()
val isP3Supported by lazy {
if (isP3Enabled) {
MixinApplication.appContext.isScreenWideColorGamut()
} else {
false
}
}
private var isP3Enabled = true

class AppColors(
val primary: Color,
Expand Down Expand Up @@ -151,9 +159,10 @@ private val LocalColors = compositionLocalOf { LightColorPalette }

@Composable
fun MixinAppTheme(
darkTheme: Boolean = MixinApplication.get().isNightMode(),
darkTheme: Boolean = if (LocalInspectionMode.current) false else MixinApplication.get().isNightMode(),
content: @Composable () -> Unit,
) {
isP3Enabled = !LocalInspectionMode.current
val colors =
if (darkTheme) {
DarkColorPalette
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package one.mixin.android.tip.wc.internal

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import one.mixin.android.Constants.DEFAULT_GAS_LIMIT_FOR_NONFUNGIBLE_TOKENS
import one.mixin.android.api.request.web3.EstimateFeeResponse
import org.web3j.protocol.core.methods.response.EthEstimateGas
Expand All @@ -9,12 +11,13 @@ import java.math.BigDecimal
import java.math.BigInteger
import java.math.RoundingMode

@Parcelize
data class TipGas(
val assetId: String,
val gasLimit: BigInteger,
val maxFeePerGas: BigInteger,
val maxPriorityFeePerGas: BigInteger,
) {
) : Parcelable {
fun selectMaxFeePerGas(maxFeePerGas: BigInteger): BigInteger {
return this.maxFeePerGas.max(maxFeePerGas)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,16 +326,17 @@ fun BrowserPage(
Box(modifier = Modifier.height(10.dp))
}
val fee = tipGas?.displayValue(transaction?.maxFeePerGas) ?: solanaFee?.stripTrailingZeros() ?: BigDecimal.ZERO
val feeSymbol = asset?.symbol ?: chain.symbol
if (fee == BigDecimal.ZERO) {
FeeInfo(
amount = "$fee",
amount = "$fee $feeSymbol",
fee = fee.multiply(asset.priceUSD()),
isFree = isFeeWaived,
onFreeClick = onFreeClick,
)
} else {
FeeInfo(
amount = "$fee ${asset?.symbol ?: ""}",
amount = "$fee $feeSymbol",
fee = fee.multiply(asset.priceUSD()),
gasPrice = tipGas?.displayGas(transaction?.maxFeePerGas)?.toPlainString(),
isFree = isFeeWaived,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class BrowserWalletBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag
const val ARGS_TO_ADDRESS = "args_to_address"
const val ARGS_TO_USER = "args_to_user"
const val ARGS_IS_FEE_FREE = "args_is_fee_free"
const val ARGS_TIP_GAS = "args_tip_gas"

fun newInstance(
jsSignMessage: JsSignMessage,
Expand All @@ -102,6 +103,7 @@ class BrowserWalletBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag
toAddress: String? = null,
toUser: User? = null,
isFeeWaived: Boolean = false,
tipGas: TipGas? = null,
) = BrowserWalletBottomSheetDialogFragment().withArgs {
putParcelable(ARGS_MESSAGE, jsSignMessage)
putString(
Expand All @@ -117,6 +119,7 @@ class BrowserWalletBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag
toAddress?.let { putString(ARGS_TO_ADDRESS, it) }
toUser?.let { putParcelable(ARGS_TO_USER, it) }
putBoolean(ARGS_IS_FEE_FREE, isFeeWaived)
tipGas?.let { putParcelable(ARGS_TIP_GAS, it) }
}
}

Expand Down Expand Up @@ -161,6 +164,7 @@ class BrowserWalletBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag
super.onViewCreated(view, savedInstanceState)
token = requireArguments().getParcelableCompat(ARGS_TOKEN, Web3TokenItem::class.java)
amount = requireArguments().getString(ARGS_AMOUNT)
tipGas = requireArguments().getParcelableCompat(ARGS_TIP_GAS, TipGas::class.java)
refreshEstimatedGasAndAsset(currentChain)
}

Expand Down Expand Up @@ -273,7 +277,8 @@ class BrowserWalletBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag
.onEach {
asset = viewModel.refreshAsset(assetId)
try {
tipGas = withContext(Dispatchers.IO) {
if (tipGas == null) {
tipGas = withContext(Dispatchers.IO) {
val r = runCatching {
viewModel.estimateFee(
EstimateFeeRequest(
Expand All @@ -291,8 +296,9 @@ class BrowserWalletBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag
ErrorHandler.handleMixinError(r?.errorCode ?: 0, r?.errorDescription ?: "")
return@withContext null
}
buildTipGas(chain.chainId, r.data!!)
} ?: return@onEach
buildTipGas(chain.chainId, r.data!!)
} ?: return@onEach
}
insufficientGas = checkGas(token, chainToken, tipGas, transaction.value, transaction.maxFeePerGas)
if (insufficientGas) {
handleException(IllegalArgumentException(requireContext().getString(R.string.insufficient_gas, chainToken?.symbol ?: currentChain.symbol)))
Expand Down Expand Up @@ -553,8 +559,9 @@ fun showBrowserBottomSheetDialogFragment(
onTxhash: ((String, String) -> Unit)? = null,
toUser: User? = null,
isFeeWaived: Boolean = false,
tipGas: TipGas? = null,
) {
val wcBottomSheet = BrowserWalletBottomSheetDialogFragment.newInstance(signMessage, currentUrl, currentTitle, amount, token, chainToken, toAddress, toUser, isFeeWaived)
val wcBottomSheet = BrowserWalletBottomSheetDialogFragment.newInstance(signMessage, currentUrl, currentTitle, amount, token, chainToken, toAddress, toUser, isFeeWaived, tipGas)
onDismiss?.let {
wcBottomSheet.setOnDismiss(onDismiss)
}
Expand Down
35 changes: 35 additions & 0 deletions app/src/main/java/one/mixin/android/ui/home/web3/Web3ViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import one.mixin.android.tip.wc.SortOrder
import one.mixin.android.tip.wc.WalletConnect
import one.mixin.android.tip.wc.WalletConnectV2
import one.mixin.android.tip.wc.internal.Chain
import one.mixin.android.tip.wc.internal.TipGas
import one.mixin.android.tip.wc.internal.buildTipGas
import one.mixin.android.ui.common.biometric.NftBiometricItem
import one.mixin.android.ui.common.biometric.maxUtxoCount
Expand Down Expand Up @@ -320,6 +321,40 @@ internal constructor(
}
}

suspend fun calcFeeWithTipGas(
token: Web3TokenItem,
transaction: JsSignMessage,
fromAddress: String,
): Pair<BigDecimal?, TipGas?> {
val chain = token.getChainFromName()
if (chain == Chain.Solana) {
val tx = VersionedTransactionCompat.from(transaction.data ?: "")
val fee = tx.calcFee(fromAddress)
return Pair(fee, null)
} else {
val r = withContext(Dispatchers.IO) {
runCatching {
web3Repository.estimateFee(
EstimateFeeRequest(
token.chainId,
null,
transaction.data ?: transaction.wcEthereumTransaction?.data,
fromAddress,
transaction.wcEthereumTransaction?.to,
transaction.wcEthereumTransaction?.value,
)
)
}.getOrNull()
}
if (r?.isSuccess != true) return Pair(BigDecimal.ZERO, null)
return withContext(Dispatchers.IO) {
val tipGas = buildTipGas(chain.chainId, r.data!!)
val fee = tipGas.displayValue(transaction.wcEthereumTransaction?.maxFeePerGas) ?: BigDecimal.ZERO
Pair(fee, tipGas)
}
}
}

suspend fun getWeb3Tx(txhash: String) = assetRepository.getWeb3Tx(txhash)

suspend fun isBlockhashValid(blockhash: String): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,10 @@ fun ParsedTxPreview(
if (parsedTx == null) {
BalanceChangeHead()
CircularProgressIndicator(
modifier = Modifier.size(32.dp),
modifier = Modifier.size(48.dp),
color = MixinAppTheme.colors.accent,
)
Box(modifier = Modifier.height(14.dp))
} else if (parsedTx.instructions?.isEmpty() == true) {
BalanceChangeHead()
Row(
Expand Down Expand Up @@ -521,6 +522,13 @@ private fun SingleBalanceChangeItem(
maxLines = 1,
fontSize = 12.sp,
)
} else {
Text(
text = " ", //holder
color = MixinAppTheme.colors.textAssist,
maxLines = 1,
fontSize = 12.sp,
)
}
}

Expand Down Expand Up @@ -558,6 +566,13 @@ private fun BalanceChangeItem(
maxLines = 1,
fontSize = 12.sp,
)
} else {
Text(
text = " ", //holder
color = MixinAppTheme.colors.textAssist,
maxLines = 1,
fontSize = 12.sp,
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,16 +326,17 @@ fun SessionRequestPage(
}
Box(modifier = Modifier.height(20.dp))

val feeSymbol = asset?.symbol ?: chain.symbol
if (fee == BigDecimal.ZERO) {
FeeInfo(
amount = "$fee",
amount = "$fee $feeSymbol",
fee = fee.multiply(asset.priceUSD()),
isFree = isFeeWaived,
onFreeClick = onFreeClick,
)
} else {
FeeInfo(
amount = "$fee ${asset?.symbol}",
amount = "$fee $feeSymbol",
fee = fee.multiply(asset.priceUSD()),
gasPrice = tipGas?.displayGas(
if (sessionRequestUI.data is WCEthereumTransaction) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import one.mixin.android.extension.viewDestroyed
import one.mixin.android.job.MixinJobManager
import one.mixin.android.job.SyncOutputJob
import one.mixin.android.session.Session
import one.mixin.android.tip.wc.internal.TipGas
import one.mixin.android.ui.address.ReceiveSelectionBottom.OnReceiveSelectionClicker
import one.mixin.android.ui.address.TransferDestinationInputFragment
import one.mixin.android.ui.common.BaseFragment
Expand Down Expand Up @@ -521,6 +522,7 @@ class InputFragment : BaseFragment(R.layout.fragment_input), OnReceiveSelectionC
toUser = user,
chainToken = chainToken,
isFeeWaived = isFeeWaived,
tipGas = tipGas,
onTxhash = { _, serializedTx ->
},
onDismiss = { isDone->
Expand Down Expand Up @@ -1034,6 +1036,7 @@ class InputFragment : BaseFragment(R.layout.fragment_input), OnReceiveSelectionC
}

private var gas: BigDecimal? = null
private var tipGas: TipGas? = null

private suspend fun refreshFee(t: TokenItem) {
val toAddress = toAddress?: return
Expand Down Expand Up @@ -1220,7 +1223,9 @@ class InputFragment : BaseFragment(R.layout.fragment_input), OnReceiveSelectionC
delay(3000)
refreshGas(t)
} else if (isAdded) {
gas = web3ViewModel.calcFee(t, transaction, fromAddress)
val feeResult = web3ViewModel.calcFeeWithTipGas(t, transaction, fromAddress)
gas = feeResult.first
tipGas = feeResult.second
if (chainToken?.assetId == t.assetId) {
val balance = runCatching {
tokenBalance.toBigDecimalOrNull()?.subtract(gas ?: BigDecimal.ZERO)
Expand Down