Adds support of Eip1559 transactions on Android wallet

This commit is contained in:
Serg
2021-11-23 15:33:07 -05:00
parent a56d07f8be
commit bb16e51deb
5 changed files with 517 additions and 42 deletions
@@ -50,6 +50,8 @@ import org.chromium.brave_wallet.mojom.ErcTokenRegistry;
import org.chromium.brave_wallet.mojom.EthJsonRpcController;
import org.chromium.brave_wallet.mojom.EthTxController;
import org.chromium.brave_wallet.mojom.EthTxControllerObserver;
import org.chromium.brave_wallet.mojom.EthereumChain;
import org.chromium.brave_wallet.mojom.GasEstimation1559;
import org.chromium.brave_wallet.mojom.KeyringController;
import org.chromium.brave_wallet.mojom.KeyringInfo;
import org.chromium.brave_wallet.mojom.SwapController;
@@ -58,6 +60,7 @@ import org.chromium.brave_wallet.mojom.SwapResponse;
import org.chromium.brave_wallet.mojom.TransactionInfo;
import org.chromium.brave_wallet.mojom.TransactionStatus;
import org.chromium.brave_wallet.mojom.TxData;
import org.chromium.brave_wallet.mojom.TxData1559;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.crypto_wallet.AssetRatioControllerFactory;
import org.chromium.chrome.browser.crypto_wallet.ERCTokenRegistryFactory;
@@ -448,10 +451,31 @@ public class BuySendSwapActivity extends AsyncInitializationActivity
TxData data = Utils.getTxData("", Utils.toWeiHex(response.gasPrice),
Utils.toWeiHex(response.estimatedGas), response.to,
Utils.toWeiHex(response.value), Utils.hexStrToNumberArray(response.data));
addUnapprovedTransaction(data, from);
sendSwapTransaction(data, from);
}
}
private void sendSwapTransaction(TxData data, String from) {
assert mAssetRatioController != null;
mAssetRatioController.getGasOracle(estimation -> {
String maxPriorityFeePerGas = "";
String maxFeePerGas = "";
if (estimation.fastMaxPriorityFeePerGas.equals(estimation.avgMaxPriorityFeePerGas)) {
// Bump fast priority fee and max fee by 1 GWei if same as average fees.
maxPriorityFeePerGas = Utils.concatHexBN(
estimation.fastMaxPriorityFeePerGas, Utils.toHexWei("1", 9));
maxFeePerGas =
Utils.concatHexBN(estimation.fastMaxFeePerGas, Utils.toHexWei("1", 9));
} else {
// Always suggest fast gas fees as default
maxPriorityFeePerGas = estimation.fastMaxPriorityFeePerGas;
maxFeePerGas = estimation.fastMaxFeePerGas;
}
data.gasPrice = "";
sendTransaction(data, from, maxPriorityFeePerGas, maxFeePerGas);
});
}
private void updateSwapControls(
SwapResponse response, boolean calculatePerSellAsset, String errorResponse) {
EditText fromValueText = findViewById(R.id.from_value_text);
@@ -794,7 +818,7 @@ public class BuySendSwapActivity extends AsyncInitializationActivity
if (mCurrentErcToken == null || mCurrentErcToken.contractAddress.isEmpty()) {
TxData data =
Utils.getTxData("", "", "", to, Utils.toHexWei(value, 18), new byte[0]);
addUnapprovedTransaction(data, from);
sendTransaction(data, from, "", "");
} else {
addUnapprovedTransactionERC20(to,
Utils.toHexWei(value, mCurrentErcToken.decimals), from,
@@ -1062,22 +1086,61 @@ public class BuySendSwapActivity extends AsyncInitializationActivity
"", "", "", mCurrentErcToken.contractAddress, "0x0", data);
String from = mCustomAccountAdapter.getTitleAtPosition(
mAccountSpinner.getSelectedItemPosition());
addUnapprovedTransaction(txData, from);
sendTransaction(txData, from, "", "");
});
}
private void addUnapprovedTransaction(TxData data, String from) {
assert mEthTxController != null;
if (mEthTxController == null) {
return;
}
mEthTxController.addUnapprovedTransaction(data, from,
(success, tx_meta_id, error_message)
-> {
// Do nothing here as we will receive an
// unapproved transaction in
// EthTxControllerObserverImpl
});
private void sendTransaction(
TxData data, String from, String maxPriorityFeePerGas, String maxFeePerGas) {
assert mEthJsonRpcController != null;
mEthJsonRpcController.getAllNetworks(networks -> {
boolean isEIP1559 = false;
// We have hardcoded EIP-1559 gas fields.
if (!maxPriorityFeePerGas.isEmpty() && !maxFeePerGas.isEmpty()) {
isEIP1559 = true;
} else if (!data.gasPrice.isEmpty()) {
// We have hardcoded legacy tx gas fields.
isEIP1559 = false;
}
for (EthereumChain network : networks) {
if (!mCurrentChainId.equals(network.chainId)) {
continue;
}
isEIP1559 = network.isEip1559;
}
assert mEthTxController != null;
if (isEIP1559) {
TxData1559 txData1559 = new TxData1559();
txData1559.baseData = data;
txData1559.chainId = mCurrentChainId;
txData1559.maxPriorityFeePerGas = maxPriorityFeePerGas;
txData1559.maxFeePerGas = maxFeePerGas;
txData1559.gasEstimation = new GasEstimation1559();
txData1559.gasEstimation.slowMaxPriorityFeePerGas = "";
txData1559.gasEstimation.slowMaxFeePerGas = "";
txData1559.gasEstimation.avgMaxPriorityFeePerGas = "";
txData1559.gasEstimation.avgMaxFeePerGas = "";
txData1559.gasEstimation.fastMaxPriorityFeePerGas = "";
txData1559.gasEstimation.fastMaxFeePerGas = "";
txData1559.gasEstimation.baseFeePerGas = "";
mEthTxController.addUnapproved1559Transaction(txData1559, from,
(success, tx_meta_id, error_message)
-> {
// Do nothing here as we will receive an
// unapproved transaction in
// EthTxControllerObserverImpl
});
} else {
mEthTxController.addUnapprovedTransaction(data, from,
(success, tx_meta_id, error_message)
-> {
// Do nothing here as we will receive an
// unapproved transaction in
// EthTxControllerObserverImpl
});
}
});
}
private void addUnapprovedTransactionERC20(
@@ -1091,7 +1154,7 @@ public class BuySendSwapActivity extends AsyncInitializationActivity
return;
}
TxData txData = Utils.getTxData("", "", "", contractAddress, "0x0", data);
addUnapprovedTransaction(txData, from);
sendTransaction(txData, from, "", "");
});
}
@@ -8,11 +8,15 @@ package org.chromium.chrome.browser.crypto_wallet.fragments;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -37,6 +41,10 @@ public class TxFragment extends Fragment {
private TransactionInfo mTxInfo;
private String mAsset;
private double mTotalPrice;
private boolean mIsEIP1559;
private int mCheckedPriorityId;
private int mPreviousCheckedPriorityId;
private double mEthRate;
public static TxFragment newInstance(TransactionInfo txInfo, String asset, double totalPrice) {
return new TxFragment(txInfo, asset, totalPrice);
@@ -68,6 +76,10 @@ public class TxFragment extends Fragment {
mTxInfo = txInfo;
mAsset = asset;
mTotalPrice = totalPrice;
mEthRate = 0;
mCheckedPriorityId = -1;
mPreviousCheckedPriorityId = -1;
mIsEIP1559 = false;
}
@Override
@@ -80,6 +92,8 @@ public class TxFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_transaction, container, false);
mIsEIP1559 = !mTxInfo.txData.maxPriorityFeePerGas.isEmpty()
&& !mTxInfo.txData.maxFeePerGas.isEmpty();
setupView(view);
@@ -90,19 +104,107 @@ public class TxFragment extends Fragment {
final Dialog dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.brave_wallet_edit_gas);
dialog.show();
mPreviousCheckedPriorityId = mCheckedPriorityId;
EditText gasFeeEdit = dialog.findViewById(R.id.gas_fee_edit);
gasFeeEdit.setText(String.format(Locale.getDefault(), "%.0f",
Utils.fromHexWei(mTxInfo.txData.baseData.gasPrice, 9)));
LinearLayout gasPriceLayout = dialog.findViewById(R.id.gas_price_layout);
LinearLayout gasLimitLayout = dialog.findViewById(R.id.gas_limit_layout);
if (!mIsEIP1559) {
EditText gasFeeEdit = dialog.findViewById(R.id.gas_fee_edit);
gasFeeEdit.setText(String.format(Locale.getDefault(), "%.0f",
Utils.fromHexWei(mTxInfo.txData.baseData.gasPrice, 9)));
EditText gasLimitEdit = dialog.findViewById(R.id.gas_limit_edit);
gasLimitEdit.setText(String.format(Locale.getDefault(), "%.0f",
Utils.fromHexGWeiToGWEI(mTxInfo.txData.baseData.gasLimit)));
EditText gasLimitEdit = dialog.findViewById(R.id.gas_limit_edit);
gasLimitEdit.setText(String.format(Locale.getDefault(), "%.0f",
Utils.fromHexGWeiToGWEI(mTxInfo.txData.baseData.gasLimit)));
} else {
TextView dialogTitle = dialog.findViewById(R.id.edit_gas_dialog_title);
dialogTitle.setText(
getResources().getString(R.string.wallet_max_priority_fee_title));
gasPriceLayout.setVisibility(View.GONE);
gasLimitLayout.setVisibility(View.GONE);
dialog.findViewById(R.id.max_priority_fee_msg).setVisibility(View.VISIBLE);
dialog.findViewById(R.id.max_priority_radio_group).setVisibility(View.VISIBLE);
RadioGroup radioGroup = dialog.findViewById(R.id.max_priority_radio_group);
radioGroup.clearCheck();
radioGroup.setOnCheckedChangeListener((group, checkedId) -> {
AssetRatioController assetRatioController = getAssetRatioController();
assert assetRatioController != null;
assetRatioController.getGasOracle(estimation -> {
mTxInfo.txData.gasEstimation = estimation;
mCheckedPriorityId = checkedId;
String gasLimit = mTxInfo.txData.baseData.gasLimit;
String maxPriorityFeePerGas = mTxInfo.txData.maxPriorityFeePerGas;
String maxFeePerGas = mTxInfo.txData.maxFeePerGas;
TextView currentBaseFeeMsg =
dialog.findViewById(R.id.current_base_fee_msg);
currentBaseFeeMsg.setVisibility(View.GONE);
LinearLayout gasAmountLimitLayout =
dialog.findViewById(R.id.gas_amount_limit_layout);
gasAmountLimitLayout.setVisibility(View.GONE);
LinearLayout perGasTipLimitLayout =
dialog.findViewById(R.id.per_gas_tip_limit_layout);
perGasTipLimitLayout.setVisibility(View.GONE);
LinearLayout perGasPriceLimitLayout =
dialog.findViewById(R.id.per_gas_price_limit_layout);
perGasPriceLimitLayout.setVisibility(View.GONE);
if (mCheckedPriorityId == R.id.radio_low) {
maxPriorityFeePerGas =
mTxInfo.txData.gasEstimation.slowMaxPriorityFeePerGas;
maxFeePerGas = mTxInfo.txData.gasEstimation.slowMaxFeePerGas;
} else if (mCheckedPriorityId == R.id.radio_optimal) {
maxPriorityFeePerGas =
mTxInfo.txData.gasEstimation.avgMaxPriorityFeePerGas;
maxFeePerGas = mTxInfo.txData.gasEstimation.avgMaxFeePerGas;
} else if (mCheckedPriorityId == R.id.radio_high) {
maxPriorityFeePerGas =
mTxInfo.txData.gasEstimation.fastMaxPriorityFeePerGas;
maxFeePerGas = mTxInfo.txData.gasEstimation.fastMaxFeePerGas;
} else if (mCheckedPriorityId == R.id.radio_custom) {
currentBaseFeeMsg.setVisibility(View.VISIBLE);
currentBaseFeeMsg.setText(String.format(
getResources().getString(R.string.wallet_current_base_fee),
String.format(Locale.getDefault(), "%.0f",
Utils.fromHexWei(
mTxInfo.txData.gasEstimation.baseFeePerGas,
9))));
gasAmountLimitLayout.setVisibility(View.VISIBLE);
EditText gasAmountLimitEdit =
dialog.findViewById(R.id.gas_amount_limit_edit);
gasAmountLimitEdit.setText(String.format(Locale.getDefault(),
"%.0f",
Utils.fromHexGWeiToGWEI(mTxInfo.txData.baseData.gasLimit)));
perGasTipLimitLayout.setVisibility(View.VISIBLE);
EditText perGasTipLimitEdit =
dialog.findViewById(R.id.per_gas_tip_limit_edit);
perGasTipLimitEdit.setText(String.format(Locale.getDefault(),
"%.0f", Utils.fromHexWei(maxPriorityFeePerGas, 9)));
perGasPriceLimitLayout.setVisibility(View.VISIBLE);
EditText perGasPriceLimitEdit =
dialog.findViewById(R.id.per_gas_price_limit_edit);
perGasPriceLimitEdit.setText(String.format(Locale.getDefault(),
"%.0f", Utils.fromHexWei(maxFeePerGas, 9)));
filterEIP1559TextWatcher.setDialog(dialog);
gasAmountLimitEdit.addTextChangedListener(filterEIP1559TextWatcher);
perGasTipLimitEdit.addTextChangedListener(filterEIP1559TextWatcher);
perGasPriceLimitEdit.addTextChangedListener(
filterEIP1559TextWatcher);
}
fillMaxFee(dialog.findViewById(R.id.maximum_fee_msg), gasLimit,
maxPriorityFeePerGas, maxFeePerGas);
});
});
if (mCheckedPriorityId == -1) {
mCheckedPriorityId = R.id.radio_optimal;
}
radioGroup.check(mCheckedPriorityId);
dialog.findViewById(R.id.maximum_fee_msg).setVisibility(View.VISIBLE);
}
Button cancel = dialog.findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCheckedPriorityId = mPreviousCheckedPriorityId;
dialog.dismiss();
}
});
@@ -110,6 +212,7 @@ public class TxFragment extends Fragment {
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPreviousCheckedPriorityId = mCheckedPriorityId;
EthTxController ethTxController = getEthTxController();
assert ethTxController != null;
if (ethTxController == null) {
@@ -117,19 +220,64 @@ public class TxFragment extends Fragment {
return;
}
mTxInfo.txData.baseData.gasPrice =
Utils.toHexWei(gasFeeEdit.getText().toString(), 9);
mTxInfo.txData.baseData.gasLimit =
Utils.toHexWeiFromGWEI(gasLimitEdit.getText().toString());
ethTxController.setGasPriceAndLimitForUnapprovedTransaction(mTxInfo.id,
mTxInfo.txData.baseData.gasPrice, mTxInfo.txData.baseData.gasLimit,
success -> {
if (!success) {
return;
}
setupView(view);
dialog.dismiss();
});
if (!mIsEIP1559) {
EditText gasLimitEdit = dialog.findViewById(R.id.gas_limit_edit);
mTxInfo.txData.baseData.gasLimit =
Utils.toHexWeiFromGWEI(gasLimitEdit.getText().toString());
EditText gasFeeEdit = dialog.findViewById(R.id.gas_fee_edit);
mTxInfo.txData.baseData.gasPrice =
Utils.toHexWei(gasFeeEdit.getText().toString(), 9);
ethTxController.setGasPriceAndLimitForUnapprovedTransaction(mTxInfo.id,
mTxInfo.txData.baseData.gasPrice,
mTxInfo.txData.baseData.gasLimit, success -> {
if (!success) {
return;
}
setupView(view);
dialog.dismiss();
});
} else {
String gasLimit = mTxInfo.txData.baseData.gasLimit;
String maxPriorityFeePerGas = mTxInfo.txData.maxPriorityFeePerGas;
String maxFeePerGas = mTxInfo.txData.maxFeePerGas;
if (mCheckedPriorityId == R.id.radio_low) {
maxPriorityFeePerGas =
mTxInfo.txData.gasEstimation.slowMaxPriorityFeePerGas;
maxFeePerGas = mTxInfo.txData.gasEstimation.slowMaxFeePerGas;
} else if (mCheckedPriorityId == R.id.radio_optimal) {
maxPriorityFeePerGas =
mTxInfo.txData.gasEstimation.avgMaxPriorityFeePerGas;
maxFeePerGas = mTxInfo.txData.gasEstimation.avgMaxFeePerGas;
} else if (mCheckedPriorityId == R.id.radio_high) {
maxPriorityFeePerGas =
mTxInfo.txData.gasEstimation.fastMaxPriorityFeePerGas;
maxFeePerGas = mTxInfo.txData.gasEstimation.fastMaxFeePerGas;
} else if (mCheckedPriorityId == R.id.radio_custom) {
EditText gasAmountLimitEdit =
dialog.findViewById(R.id.gas_amount_limit_edit);
EditText perGasTipLimitEdit =
dialog.findViewById(R.id.per_gas_tip_limit_edit);
EditText perGasPriceLimitEdit =
dialog.findViewById(R.id.per_gas_price_limit_edit);
gasLimit = Utils.toHexWeiFromGWEI(
gasAmountLimitEdit.getText().toString());
maxPriorityFeePerGas =
Utils.toHexWei(perGasTipLimitEdit.getText().toString(), 9);
maxFeePerGas = Utils.toHexWei(
perGasPriceLimitEdit.getText().toString(), 9);
}
mTxInfo.txData.baseData.gasLimit = gasLimit;
mTxInfo.txData.maxPriorityFeePerGas = maxPriorityFeePerGas;
mTxInfo.txData.maxFeePerGas = maxFeePerGas;
ethTxController.setGasFeeAndLimitForUnapprovedTransaction(mTxInfo.id,
maxPriorityFeePerGas, maxFeePerGas, gasLimit, success -> {
if (!success) {
return;
}
setupView(view);
dialog.dismiss();
});
}
}
});
}
@@ -138,11 +286,57 @@ public class TxFragment extends Fragment {
return view;
}
private TextWatcherImpl filterEIP1559TextWatcher = new TextWatcherImpl();
private class TextWatcherImpl implements TextWatcher {
Dialog mDialog;
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
EditText gasAmountLimitEdit = mDialog.findViewById(R.id.gas_amount_limit_edit);
EditText perGasTipLimitEdit = mDialog.findViewById(R.id.per_gas_tip_limit_edit);
EditText perGasPriceLimitEdit = mDialog.findViewById(R.id.per_gas_price_limit_edit);
if (gasAmountLimitEdit.hasFocus() || perGasTipLimitEdit.hasFocus()
|| perGasPriceLimitEdit.hasFocus()) {
fillMaxFee(mDialog.findViewById(R.id.maximum_fee_msg),
Utils.toHexWeiFromGWEI(gasAmountLimitEdit.getText().toString()),
Utils.toHexWei(perGasTipLimitEdit.getText().toString(), 9),
Utils.toHexWei(perGasPriceLimitEdit.getText().toString(), 9));
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {}
};
private void fillMaxFee(
TextView textView, String gasLimit, String maxPriorityFeePerGas, String maxFeePerGas) {
double totalGas =
Utils.fromHexWei(Utils.multiplyHexBN(gasLimit,
Utils.concatHexBN(maxPriorityFeePerGas, maxFeePerGas)),
18);
double price = totalGas * mEthRate;
textView.setText(String.format(getResources().getString(R.string.wallet_maximum_fee),
String.format(Locale.getDefault(), "%.2f", price),
String.format(Locale.getDefault(), "%.8f", totalGas)));
}
private void setupView(View view) {
TextView gasFeeAmount = view.findViewById(R.id.gas_fee_amount);
final double totalGas =
Utils.fromHexWei(Utils.multiplyHexBN(mTxInfo.txData.baseData.gasLimit,
mTxInfo.txData.baseData.gasPrice),
final double totalGas = mIsEIP1559
? Utils.fromHexWei(Utils.multiplyHexBN(mTxInfo.txData.baseData.gasLimit,
Utils.concatHexBN(mTxInfo.txData.maxPriorityFeePerGas,
mTxInfo.txData.maxFeePerGas)),
18)
: Utils.fromHexWei(Utils.multiplyHexBN(mTxInfo.txData.baseData.gasLimit,
mTxInfo.txData.baseData.gasPrice),
18);
gasFeeAmount.setText(
String.format(getResources().getString(R.string.crypto_wallet_gas_fee_amount),
@@ -165,8 +359,8 @@ public class TxFragment extends Fragment {
if (!success || values.length == 0) {
return;
}
double price = Double.valueOf(values[0].price);
double totalPrice = totalGas * price;
mEthRate = Double.valueOf(values[0].price);
double totalPrice = totalGas * mEthRate;
TextView gasFeeAmountFiat = view.findViewById(R.id.gas_fee_amount_fiat);
gasFeeAmountFiat.setText(String.format(
getResources().getString(R.string.crypto_wallet_amount_fiat),
@@ -527,6 +527,21 @@ public class Utils {
return "0x" + res.toString(16);
}
public static String concatHexBN(String number1, String number2) {
if (number1.startsWith("0x")) {
number1 = number1.substring(2);
}
if (number2.startsWith("0x")) {
number2 = number2.substring(2);
}
BigInteger bigNumber1 = new BigInteger(number1, 16);
BigInteger bigNumber2 = new BigInteger(number2, 16);
BigInteger res = bigNumber1.add(bigNumber2);
return "0x" + res.toString(16);
}
public static byte[] hexStrToNumberArray(String value) {
if (value.startsWith("0x")) {
value = value.substring(2);
@@ -6,7 +6,20 @@
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/edit_gas_dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_edit_gas_title"
android:textSize="18sp" />
<LinearLayout
android:id="@+id/gas_price_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
@@ -34,6 +47,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/gas_limit_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
@@ -60,6 +74,159 @@
</LinearLayout>
<TextView
android:id="@+id/max_priority_fee_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_max_priority_fee_msg"
android:visibility = "gone"
android:textSize="14sp" />
<RadioGroup
android:id="@+id/max_priority_radio_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility = "gone"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_low"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/wallet_max_priority_fee_low"/>
<RadioButton android:id="@+id/radio_optimal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/wallet_max_priority_fee_optimal"/>
<RadioButton android:id="@+id/radio_high"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/wallet_max_priority_fee_high"/>
<RadioButton android:id="@+id/radio_custom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/wallet_max_priority_fee_custom"/>
</RadioGroup>
<TextView
android:id="@+id/current_base_fee_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_current_base_fee"
android:visibility = "gone"
android:textSize="16sp" />
<LinearLayout
android:id="@+id/gas_amount_limit_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility = "gone"
android:orientation="horizontal">
<TextView
android:layout_width="180dp"
android:layout_height="wrap_content"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_max_priority_gas_amount_limit"
android:textSize="14sp" />
<EditText
android:id="@+id/gas_amount_limit_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textColor="@color/wallet_text_color"
android:textSize="14sp"
tools:ignore="LabelFor, Autofill" />
</LinearLayout>
<LinearLayout
android:id="@+id/per_gas_tip_limit_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility = "gone"
android:orientation="horizontal">
<TextView
android:layout_width="180dp"
android:layout_height="wrap_content"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_max_priority_per_gas_tip_limit"
android:textSize="14sp" />
<EditText
android:id="@+id/per_gas_tip_limit_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textColor="@color/wallet_text_color"
android:textSize="14sp"
tools:ignore="LabelFor, Autofill" />
</LinearLayout>
<LinearLayout
android:id="@+id/per_gas_price_limit_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility = "gone"
android:orientation="horizontal">
<TextView
android:layout_width="180dp"
android:layout_height="wrap_content"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_max_priority_per_gas_price_limit"
android:textSize="14sp" />
<EditText
android:id="@+id/per_gas_price_limit_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textColor="@color/wallet_text_color"
android:textSize="14sp"
tools:ignore="LabelFor, Autofill" />
</LinearLayout>
<TextView
android:id="@+id/maximum_fee_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:textColor="@color/wallet_text_color"
android:text="@string/wallet_maximum_fee"
android:visibility = "gone"
android:textSize="16sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"