Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatable with new swap api #4893

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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 @@ -5,9 +5,11 @@ import one.mixin.android.api.response.web3.JupiterQuoteResponse
data class SwapRequest(
val payer: String,
val inputMint: String,
val inAmount: Long,
val inputAmount: String, // exin
val inputAmount: String,
val outputMint: String,
val outputAmount: String,
val inputChainId: Int,
val outputChainId: Int,
val slippage: Int,
val source: String,

Expand Down
62 changes: 57 additions & 5 deletions app/src/main/java/one/mixin/android/api/response/Web3Token.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import one.mixin.android.api.response.web3.Swappable
import one.mixin.android.extension.base64Encode
import one.mixin.android.tip.wc.internal.Chain
import one.mixin.android.tip.wc.internal.WCEthereumTransaction
import one.mixin.android.web3.ChainType
import one.mixin.android.web3.Web3Exception
import one.mixin.android.web3.js.JsSignMessage
import one.mixin.android.web3.js.JsSigner
Expand Down Expand Up @@ -90,7 +91,7 @@ class Web3Token(

override fun toSwapToken(): SwapToken {
return SwapToken(
address = if (assetKey == solanaNativeTokenAssetKey) wrappedSolTokenAssetKey else assetKey,
address = getUnique(),
assetId = "",
decimals = decimals,
name = name,
Expand All @@ -105,19 +106,33 @@ class Web3Token(
icon = chainIconUrl,
price = null,
),
web3ChainId = getWeb3ChainId(),
balance = balance,
price = price,
)
}

override fun getUnique(): String {
return if (assetKey == solanaNativeTokenAssetKey) wrappedSolTokenAssetKey else assetKey
return when (assetKey) {
solanaNativeTokenAssetKey -> {
wrappedSolTokenAssetKey
}
polygonNativeTokenAssetKey -> {
eip155NativeTokenAssetKey
}
else -> {
assetKey
}
}
}
}

const val solanaNativeTokenAssetKey = "11111111111111111111111111111111"
const val wrappedSolTokenAssetKey = "So11111111111111111111111111111111111111112"

const val polygonNativeTokenAssetKey = "0x0000000000000000000000000000000000001010"
const val eip155NativeTokenAssetKey = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"

fun Web3Token.getChainFromName(): Chain {
return when {
chainName.equals("ethereum", true) -> Chain.Ethereum
Expand Down Expand Up @@ -152,6 +167,15 @@ fun Web3Token.isSolana(): Boolean {
return chainName.equals("solana", true)
}

fun Web3Token.getWeb3ChainId(): Int {
return when {
chainName.equals("ethereum", true) -> Web3ChainId.EthChainId
chainName.equals("polygon", true) -> Web3ChainId.PolygonChainId
chainName.equals("solana", true) -> Web3ChainId.SolanaChainId
else -> Web3ChainId.MixinChainId
}
}

fun Web3Token.isSolToken(): Boolean {
return isSolana() && (assetKey == solanaNativeTokenAssetKey || assetKey == wrappedSolTokenAssetKey)
}
Expand Down Expand Up @@ -264,9 +288,9 @@ suspend fun Web3Token.buildTransaction(
)
transaction.addPlaceholderSignature()
val tx = transaction.serialize().base64Encode()
return JsSignMessage(0, JsSignMessage.TYPE_RAW_TRANSACTION, data = tx, solanaTxSource = SolanaTxSource.InnerTransfer)
return JsSignMessage(0, JsSignMessage.TYPE_RAW_TRANSACTION, Web3ChainId.SolanaChainId, data = tx, solanaTxSource = SolanaTxSource.InnerTransfer)
} else {
JsSigner.useEvm()
JsSigner.useEip155(getWeb3ChainId())
val transaction =
if ((chainName.equals("ethereum", true) && assetKey == "0x0000000000000000000000000000000000000000") ||
(chainName.equals("base", true) && assetKey == "0x0000000000000000000000000000000000000000") ||
Expand Down Expand Up @@ -294,7 +318,7 @@ suspend fun Web3Token.buildTransaction(
val data = FunctionEncoder.encode(function)
WCEthereumTransaction(fromAddress, assetKey, null, null, null, null, null, null, "0x0", data)
}
return JsSignMessage(0, JsSignMessage.TYPE_TRANSACTION, transaction)
return JsSignMessage(0, JsSignMessage.TYPE_TRANSACTION, getWeb3ChainId(), transaction)
}
}

Expand Down Expand Up @@ -333,3 +357,31 @@ fun Web3Token.copy(
fun Long.solLamportToAmount(scale: Int = 9): BigDecimal {
return BigDecimal(this).divide(BigDecimal.TEN.pow(9)).setScale(scale, RoundingMode.CEILING)
}

@Suppress("ConstPropertyName")
object Web3ChainId {
// bip44
const val BtcChainId = 0
const val SolanaChainId = 501
const val MixinChainId = 2365

// eip155
const val EthChainId = 1
const val PolygonChainId = 137

fun getChainType(id: Int): ChainType {
return when(id) {
EthChainId, PolygonChainId -> ChainType.ethereum
SolanaChainId -> ChainType.solana
else -> ChainType.solana
}
}

fun getChain(id: Int): Chain {
return when(id) {
EthChainId -> Chain.Ethereum
PolygonChainId -> Chain.Polygon
else -> Chain.Solana
}
}
}
10 changes: 10 additions & 0 deletions app/src/main/java/one/mixin/android/api/response/web3/SwapToken.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package one.mixin.android.api.response.web3
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import one.mixin.android.api.response.Web3ChainId
import one.mixin.android.api.response.polygonNativeTokenAssetKey
import one.mixin.android.api.response.solanaNativeTokenAssetKey
import one.mixin.android.api.response.wrappedSolTokenAssetKey
import java.math.BigDecimal
Expand All @@ -18,6 +20,7 @@ data class SwapToken(
@SerializedName("symbol") val symbol: String,
@SerializedName("icon") val icon: String,
@SerializedName("chain") val chain: SwapChain,
@SerializedName("web3ChainId") val web3ChainId: Int,
var price: String? = null,
var balance: String? = null,
) : Parcelable {
Expand Down Expand Up @@ -55,6 +58,13 @@ data class SwapToken(
}
}

fun getWeb3ApiAddress(): String {
if (web3ChainId == Web3ChainId.PolygonChainId) {
return polygonNativeTokenAssetKey
}
return address
}

fun inMixin(): Boolean = assetId != ""

override fun equals(other: Any?): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ interface RouteService {
@GET("web3/tokens")
suspend fun web3Tokens(
@Query("source") source: String,
@Query("web3ChainId") web3ChainId: Int,
@Query("version") version: String = BuildConfig.VERSION_NAME,
): MixinResponse<List<SwapToken>>

Expand All @@ -113,6 +114,8 @@ interface RouteService {
@Query("inputMint") inputMint: String,
@Query("outputMint") outputMint: String,
@Query("amount") amount: String,
@Query("inputChainId") inputChainId: Int,
@Query("outputChainId") outputChainId: Int,
@Query("slippage") slippage: String,
@Query("source") source: String,
): MixinResponse<QuoteResponse>
Expand Down Expand Up @@ -140,11 +143,13 @@ interface RouteService {
@GET("web3/tokens/{address}")
suspend fun getSwapToken(
@Path("address") address: String,
@Query("web3ChainId") web3ChainId: Int,
): MixinResponse<SwapToken?>

@GET("web3/tokens/search/{query}")
suspend fun searchTokens(
@Path("query") query: String,
@Query("web3ChainId") web3ChainId: Int,
): MixinResponse<List<SwapToken>>

@POST("web3/stake")
Expand Down
10 changes: 5 additions & 5 deletions app/src/main/java/one/mixin/android/tip/wc/internal/TipGas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ data class TipGas(
tx: WCEthereumTransaction,
) : this(
assetId,
gasPrice.max(tx.gasPrice?.run { Numeric.toBigInt(this) } ?: BigInteger.ZERO),
gasLimit.max(tx.gasLimit?.run { Numeric.toBigInt(this) } ?: BigInteger.ZERO).run {
gasPrice.max(tx.gasPrice?.run { Numeric.decodeQuantity(this) } ?: BigInteger.ZERO),
gasLimit.max(tx.gasLimit?.run { Numeric.decodeQuantity(this) } ?: BigInteger.ZERO).run {
if (this == BigInteger.ZERO) {
this
} else {
this.plus(this.divide(BigInteger.valueOf(2)))
}
},
ethMaxPriorityFeePerGas.max(tx.maxPriorityFeePerGas?.run { Numeric.toBigInt(this) } ?: BigInteger.ZERO),
ethMaxPriorityFeePerGas.max(tx.maxPriorityFeePerGas?.run { Numeric.decodeQuantity(this) } ?: BigInteger.ZERO),
)

fun maxFeePerGas(maxFeePerGas: BigInteger): BigInteger {
Expand All @@ -39,13 +39,13 @@ data class TipGas(
}

fun TipGas.displayValue(maxFee: String?): BigDecimal? {
val maxFeePerGas = maxFee?.let { Numeric.toBigInt(it) } ?: BigInteger.ZERO
val maxFeePerGas = maxFee?.let { Numeric.decodeQuantity(it) } ?: BigInteger.ZERO
val gas = maxFeePerGas(maxFeePerGas)
return Convert.fromWei(gas.run { BigDecimal(this) }.multiply(gasLimit.run { BigDecimal(this) }), Convert.Unit.ETHER)
}

fun TipGas.displayGas(maxFee: String?): BigDecimal? {
val maxFeePerGas = maxFee?.let { Numeric.toBigInt(it) } ?: BigInteger.ZERO
val maxFeePerGas = maxFee?.let { Numeric.decodeQuantity(it) } ?: BigInteger.ZERO
val gas = maxFeePerGas(maxFeePerGas)
return Convert.fromWei(gas.run { BigDecimal(this) }, Convert.Unit.GWEI).setScale(2, RoundingMode.UP)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ val ethTransactionSerializer =
fun WCEthereumTransaction.toTransaction(): Transaction {
return Transaction(
from,
nonce?.let { Numeric.toBigInt(it) },
gasPrice?.let { Numeric.toBigInt(it) },
gasLimit?.let { Numeric.toBigInt(it) },
nonce?.let { Numeric.decodeQuantity(it) },
gasPrice?.let { Numeric.decodeQuantity(it) },
gasLimit?.let { Numeric.decodeQuantity(it) },
to,
value?.let { Numeric.toBigInt(it) },
value?.let { Numeric.decodeQuantity(it) },
data,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import one.mixin.android.api.response.MultisigsResponse
import one.mixin.android.api.response.NonFungibleOutputResponse
import one.mixin.android.api.response.PaymentCodeResponse
import one.mixin.android.api.response.PaymentStatus
import one.mixin.android.api.response.Web3ChainId
import one.mixin.android.api.response.getScopes
import one.mixin.android.api.response.signature.SignatureState
import one.mixin.android.databinding.FragmentBottomSheetBinding
Expand Down Expand Up @@ -933,7 +934,7 @@ class LinkBottomSheetDialogFragment : BottomSheetDialogFragment() {
.showIfNotShowing(childFragmentManager, WalletUnlockBottomSheetDialogFragment.TAG)
return true
}
val signMessage = JsSignMessage(0, JsSignMessage.TYPE_RAW_TRANSACTION, data = data, solanaTxSource = SolanaTxSource.Link)
val signMessage = JsSignMessage(0, JsSignMessage.TYPE_RAW_TRANSACTION, Web3ChainId.SolanaChainId, data = data, solanaTxSource = SolanaTxSource.Link)
BrowserWalletBottomSheetDialogFragment.newInstance(signMessage, null, null)
.setOnDismiss { dismiss() }
.setOnTxhash { sig, _ ->
Expand All @@ -953,7 +954,7 @@ class LinkBottomSheetDialogFragment : BottomSheetDialogFragment() {
val input = uri.getQueryParameter("input")
val output = uri.getQueryParameter("output")
val amount = uri.getQueryParameter("amount")
SwapActivity.show(requireContext(), input, output, amount)
SwapActivity.show(requireContext(), Web3ChainId.MixinChainId, input, output, amount)
dismiss()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ fun BrowserPage(
TransactionPreview(
balance =
Convert.fromWei(
Numeric.toBigInt(transaction?.value ?: "0").toBigDecimal(),
Numeric.decodeQuantity(transaction?.value ?: "0").toBigDecimal(),
Convert.Unit.ETHER,
),
chain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import one.mixin.android.R
import one.mixin.android.api.request.web3.PriorityLevel
import one.mixin.android.api.response.Web3ChainId
import one.mixin.android.api.response.Web3Token
import one.mixin.android.api.response.getChainFromName
import one.mixin.android.api.response.web3.ParsedTx
Expand Down Expand Up @@ -127,7 +128,7 @@ class BrowserWalletBottomSheetDialogFragment : BottomSheetDialogFragment() {
requireArguments().getParcelableCompat(ARGS_CHAIN_TOKEN, Web3Token::class.java)
}
private val currentChain by lazy {
token?.getChainFromName() ?: JsSigner.currentChain
Web3ChainId.getChain(signMessage.web3ChainId)
}

var step by mutableStateOf(Step.Input)
Expand Down Expand Up @@ -251,8 +252,8 @@ class BrowserWalletBottomSheetDialogFragment : BottomSheetDialogFragment() {
.onEach {
asset = viewModel.refreshAsset(assetId)
try {
val gasPrice = viewModel.ethGasPrice(chain) ?: return@onEach
val gasLimit = viewModel.ethGasLimit(chain, transaction.toTransaction()) ?: return@onEach
val gasPrice = viewModel.ethGasPrice(chain) ?: return@onEach
val gasLimit = viewModel.ethGasLimit(chain, transaction.toTransaction()) ?: return@onEach
val maxPriorityFeePerGas = viewModel.ethMaxPriorityFeePerGas(chain) ?: return@onEach
tipGas = TipGas(chain.chainId, gasPrice, gasLimit, maxPriorityFeePerGas, transaction)
insufficientGas = checkGas(token, chainToken, tipGas, transaction.value, transaction.maxFeePerGas)
Expand Down Expand Up @@ -387,7 +388,7 @@ class BrowserWalletBottomSheetDialogFragment : BottomSheetDialogFragment() {
} else if (tipGas != null) {
val maxGas = tipGas.displayValue(maxFeePerGas) ?: BigDecimal.ZERO
if (web3Token.fungibleId == chainToken.fungibleId && web3Token.chainId == chainToken.chainId) {
Convert.fromWei(Numeric.toBigInt(value ?: "0x0").toBigDecimal(), Convert.Unit.ETHER) + maxGas > BigDecimal(chainToken.balance)
Convert.fromWei(Numeric.decodeQuantity(value ?: "0x0").toBigDecimal(), Convert.Unit.ETHER) + maxGas > BigDecimal(chainToken.balance)
} else {
maxGas > BigDecimal(chainToken.balance)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class BrowserWalletBottomSheetViewModel
transaction: Transaction,
) = withContext(Dispatchers.IO) {
WalletConnectV2.ethEstimateGas(chain, transaction)?.run {
val defaultLimit = if (chain.chainReference == Chain.Ethereum.chainReference) BigInteger.valueOf(4712380L) else null
val defaultLimit = if (chain == Chain.Ethereum || chain == Chain.Polygon) BigInteger.valueOf(4712380L) else null
convertToGasLimit(this, defaultLimit)
}
}
Expand All @@ -61,9 +61,9 @@ class BrowserWalletBottomSheetViewModel
} else {
BigInteger.ZERO
}
} else if (estimate.amountUsed.compareTo(BigInteger.ZERO) > 0) {
} else if (estimate.amountUsed > BigInteger.ZERO) {
estimate.amountUsed
} else if (defaultLimit == null || defaultLimit.equals(BigInteger.ZERO)) {
} else if (defaultLimit == null || defaultLimit == BigInteger.ZERO) {
BigInteger(DEFAULT_GAS_LIMIT_FOR_NONFUNGIBLE_TOKENS)
} else {
defaultLimit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import one.mixin.android.MixinApplication
import one.mixin.android.R
import one.mixin.android.RxBus
import one.mixin.android.api.MixinResponseException
import one.mixin.android.api.response.Web3ChainId
import one.mixin.android.api.response.Web3Token
import one.mixin.android.api.response.findChainToken
import one.mixin.android.databinding.FragmentChainBinding
Expand All @@ -43,6 +44,7 @@ import one.mixin.android.extension.toast
import one.mixin.android.session.Session
import one.mixin.android.tip.wc.WCUnlockEvent
import one.mixin.android.ui.common.BaseFragment
import one.mixin.android.ui.home.web3.swap.SwapFragment
import one.mixin.android.ui.tip.wc.WalletConnectFragment
import one.mixin.android.ui.tip.wc.WalletUnlockBottomSheetDialogFragment
import one.mixin.android.ui.tip.wc.WalletUnlockBottomSheetDialogFragment.Companion.TYPE_ETH
Expand Down Expand Up @@ -89,6 +91,10 @@ class EthereumFragment : BaseFragment() {
navTo(Web3ReceiveSelectionFragment(), Web3ReceiveSelectionFragment.TAG)
}

R.id.swap -> {
navTo(SwapFragment.newInstance(Web3ChainId.EthChainId, tokens), SwapFragment.TAG)
}

R.id.browser -> {
navTo(SearchDappFragment(), SearchDappFragment.TAG)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import one.mixin.android.MixinApplication
import one.mixin.android.R
import one.mixin.android.RxBus
import one.mixin.android.api.MixinResponseException
import one.mixin.android.api.response.Web3ChainId
import one.mixin.android.api.response.Web3Token
import one.mixin.android.api.response.findChainToken
import one.mixin.android.api.response.isSolToken
Expand Down Expand Up @@ -97,7 +98,7 @@ class SolanaFragment : BaseFragment() {
}

R.id.swap -> {
navTo(SwapFragment.newInstance(tokens), SwapFragment.TAG)
navTo(SwapFragment.newInstance(Web3ChainId.SolanaChainId, tokens), SwapFragment.TAG)
}

R.id.browser -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ class Web3WalletAdapter(val chainId: String) : RecyclerView.Adapter<RecyclerView
} else if (viewType == 1) {
Web3HeaderHolder(ItemWeb3HeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)).apply {
this.binding.header.setTitle(if (chainId == Constants.ChainId.SOLANA_CHAIN_ID) R.string.Solana_Account else R.string.Ethereum_Account)
if (chainId == Constants.ChainId.SOLANA_CHAIN_ID) this.binding.header.enableSwap()
if (chainId == Constants.ChainId.SOLANA_CHAIN_ID || chainId == Constants.ChainId.ETHEREUM_CHAIN_ID) {
this.binding.header.enableSwap()
}
}
} else {
Web3Holder(ItemWeb3TokenBinding.inflate(LayoutInflater.from(parent.context), parent, false))
Expand Down
Loading
Loading