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

Improve gas calc #3356

Merged
merged 2 commits into from
Feb 10, 2024
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
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ android {
def DEFUALT_WALLETCONNECT_PROJECT_ID = "\"40c6071febfd93f4fe485c232a8a4cd9\""
def DEFAULT_AURORA_API_KEY = "\"HFDDY5BNKGXBB82DE2G8S64C3C41B76PYI\""; //Put your Aurorascan.dev API key here - this one will rate limit as it is common

buildConfigField 'int', 'DB_VERSION', '53'
buildConfigField 'int', 'DB_VERSION', '54'

buildConfigField "String", XInfuraAPI, DEFAULT_INFURA_API_KEY
buildConfigField "String", "WALLETCONNECT_PROJECT_ID", DEFUALT_WALLETCONNECT_PROJECT_ID
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.alphawallet.app.entity;

import android.content.Intent;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultLauncher;

import com.alphawallet.app.web3.entity.Web3Transaction;

Expand Down Expand Up @@ -58,4 +61,14 @@
default void setCurrentGasIndex(ActivityResult result)
{
}

default ActivityResultLauncher<Intent> gasSelectLauncher()
{
return null;

Check warning on line 67 in app/src/main/java/com/alphawallet/app/entity/ActionSheetInterface.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/ActionSheetInterface.java#L67

Added line #L67 was not covered by tests
}

default void gasEstimateReady()
{

}

Check warning on line 73 in app/src/main/java/com/alphawallet/app/entity/ActionSheetInterface.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/ActionSheetInterface.java#L73

Added line #L73 was not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import javax.annotation.Nullable;

import timber.log.Timber;

/**
* Created by JB on 20/01/2022.
*/
Expand Down Expand Up @@ -165,6 +167,66 @@
hasLockedGas = false;
}

public GasPriceSpread(Context ctx, String apiReturn) //ChainId is unused but we need to disambiguate from etherscan API return
{
this.timeStamp = System.currentTimeMillis();
BigDecimal rBaseFee = BigDecimal.ZERO;
hasLockedGas = false;

Check warning on line 174 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L171-L174

Added lines #L171 - L174 were not covered by tests

try
{
JSONObject result = new JSONObject(apiReturn);

Check warning on line 178 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L178

Added line #L178 was not covered by tests
if (result.has("estimatedBaseFee"))
{
rBaseFee = new BigDecimal(result.getString("estimatedBaseFee"));

Check warning on line 181 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L181

Added line #L181 was not covered by tests
}

EIP1559FeeOracleResult low = readFeeResult(result, "low", rBaseFee);
EIP1559FeeOracleResult medium = readFeeResult(result, "medium", rBaseFee);
EIP1559FeeOracleResult high = readFeeResult(result, "high", rBaseFee);

Check warning on line 186 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L184-L186

Added lines #L184 - L186 were not covered by tests

if (low == null || medium == null || high == null)
{
return;

Check warning on line 190 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L190

Added line #L190 was not covered by tests
}

BigInteger rapidPriorityFee = (new BigDecimal(high.priorityFee)).multiply(BigDecimal.valueOf(1.2)).toBigInteger();
EIP1559FeeOracleResult rapid = new EIP1559FeeOracleResult(high.maxFeePerGas, rapidPriorityFee, gweiToWei(rBaseFee));

Check warning on line 194 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L193-L194

Added lines #L193 - L194 were not covered by tests

fees.put(TXSpeed.SLOW, new GasSpeed(ctx.getString(R.string.speed_slow), SLOW_SECONDS, low));
fees.put(TXSpeed.STANDARD, new GasSpeed(ctx.getString(R.string.speed_average), STANDARD_SECONDS, medium));
fees.put(TXSpeed.FAST, new GasSpeed(ctx.getString(R.string.speed_fast), FAST_SECONDS, high));
fees.put(TXSpeed.RAPID, new GasSpeed(ctx.getString(R.string.speed_rapid), RAPID_SECONDS, rapid));

Check warning on line 199 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L196-L199

Added lines #L196 - L199 were not covered by tests
}
catch (JSONException e)

Check warning on line 201 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L201

Added line #L201 was not covered by tests
{
//
}
}

Check warning on line 205 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L204-L205

Added lines #L204 - L205 were not covered by tests

private EIP1559FeeOracleResult readFeeResult(JSONObject result, String speed, BigDecimal rBaseFee)
{
EIP1559FeeOracleResult oracleResult = null;

Check warning on line 209 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L209

Added line #L209 was not covered by tests

try
{
if (result.has(speed))
{
JSONObject thisSpeed = result.getJSONObject(speed);
BigDecimal maxFeePerGas = new BigDecimal(thisSpeed.getString("suggestedMaxFeePerGas"));
BigDecimal priorityFee = new BigDecimal(thisSpeed.getString("suggestedMaxPriorityFeePerGas"));
oracleResult = new EIP1559FeeOracleResult(gweiToWei(maxFeePerGas), gweiToWei(priorityFee), gweiToWei(rBaseFee));

Check warning on line 218 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L215-L218

Added lines #L215 - L218 were not covered by tests
}
}
catch (Exception e)

Check warning on line 221 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L221

Added line #L221 was not covered by tests
{
Timber.e("Infura GasOracle read failing; please adjust your Infura API settings.");
}

Check warning on line 224 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L223-L224

Added lines #L223 - L224 were not covered by tests

return oracleResult;

Check warning on line 226 in app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/entity/GasPriceSpread.java#L226

Added line #L226 was not covered by tests
}

// For etherscan return
public GasPriceSpread(String apiReturn)
{
this.timeStamp = System.currentTimeMillis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,18 @@ else if (!realmData.hasField("attestation"))

oldVersion = 53;
}

if (oldVersion == 53)
{
RealmObjectSchema realmData = schema.get("Realm1559Gas");
if (realmData != null) schema.remove("Realm1559Gas");
schema.create("Realm1559Gas")
.addField("chainId", long.class, FieldAttribute.PRIMARY_KEY)
.addField("timeStamp", long.class)
.addField("resultData", String.class);

oldVersion = 54;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@

private static final KeyProvider keyProvider = KeyProviderFactory.get();
public static final boolean usesProductionKey = !keyProvider.getInfuraKey().equals(DEFAULT_INFURA_KEY);
private static final String INFURA_GAS_API = "https://gas.api.infura.io/networks/CHAIN_ID/suggestedGasFees";

public static final String FREE_MAINNET_RPC_URL = "https://rpc.ankr.com/eth";
public static final String FREE_POLYGON_RPC_URL = "https://polygon-rpc.com";
Expand Down Expand Up @@ -493,7 +494,9 @@
//Add it to this list here if so. Note that so far, all gas oracles follow the same format:
// <etherscanAPI from the above list> + GAS_API
//If the gas oracle you're adding doesn't follow this spec then you'll have to change the getGasOracle method
private static final List<Long> hasGasOracleAPI = Arrays.asList(MAINNET_ID, HECO_ID, BINANCE_MAIN_ID, POLYGON_ID);
private static final List<Long> hasGasOracleAPI = Arrays.asList(MAINNET_ID, POLYGON_ID, ARBITRUM_MAIN_ID, AVALANCHE_ID, BINANCE_MAIN_ID, CRONOS_MAIN_ID, GOERLI_ID,
SEPOLIA_TESTNET_ID, FANTOM_ID, LINEA_ID, OPTIMISTIC_MAIN_ID, POLYGON_TEST_ID);
private static final List<Long> hasEtherscanGasOracleAPI = Arrays.asList(MAINNET_ID, HECO_ID, BINANCE_MAIN_ID, POLYGON_ID);
private static final List<Long> hasBlockNativeGasOracleAPI = Arrays.asList(MAINNET_ID, POLYGON_ID);
//These chains don't allow custom gas
private static final List<Long> hasLockedGas = Arrays.asList(KLAYTN_ID, KLAYTN_BAOBAB_ID);
Expand All @@ -508,11 +511,24 @@
}
};

public static String getEtherscanGasOracle(long chainId)
{
if (hasEtherscanGasOracleAPI.contains(chainId) && networkMap.indexOfKey(chainId) >= 0)
{
return networkMap.get(chainId).etherscanAPI + GAS_API;

Check warning on line 518 in app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java#L518

Added line #L518 was not covered by tests
}
else
{
return "";

Check warning on line 522 in app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java#L522

Added line #L522 was not covered by tests
}
}

public static String getGasOracle(long chainId)
{
if (hasGasOracleAPI.contains(chainId) && networkMap.indexOfKey(chainId) >= 0)
{
return networkMap.get(chainId).etherscanAPI + GAS_API;
//construct API route:
return INFURA_GAS_API.replace("CHAIN_ID", Long.toString(chainId));

Check warning on line 531 in app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java#L531

Added line #L531 was not covered by tests
}
else
{
Expand Down Expand Up @@ -603,7 +619,9 @@
public static int getBatchProcessingLimit(long chainId)
{
if (batchProcessingLimitMap.size() == 0) setBatchProcessingLimits(); //If batch limits not set, init them and proceed
return batchProcessingLimitMap.get(chainId, 0); //default to zero / no batching
{
return batchProcessingLimitMap.get(chainId, 0); //default to zero / no batching

Check warning on line 623 in app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java#L623

Added line #L623 was not covered by tests
}
}

@Override
Expand Down Expand Up @@ -861,8 +879,6 @@
return networkMap.get(chainId);
}

// fetches the last transaction nonce; if it's identical to the last used one then increment by one
// to ensure we don't get transaction replacement
@Override
public Single<BigInteger> getLastTransactionNonce(Web3j web3j, String walletAddress)
{
Expand All @@ -871,7 +887,7 @@
try
{
EthGetTransactionCount ethGetTransactionCount = web3j
.ethGetTransactionCount(walletAddress, DefaultBlockParameterName.LATEST)
.ethGetTransactionCount(walletAddress, DefaultBlockParameterName.PENDING)

Check warning on line 890 in app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java#L890

Added line #L890 was not covered by tests
.send();
return ethGetTransactionCount.getTransactionCount();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,9 @@
service.addHeader("Authorization", "Basic " + infuraKey);
}
}

public static void addInfuraGasCredentials(Request.Builder service, String infuraSecret)
{
service.addHeader("Authorization", "Basic " + infuraSecret);
}

Check warning on line 45 in app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java#L44-L45

Added lines #L44 - L45 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.alphawallet.app.entity.Transaction;
import com.alphawallet.app.entity.TransactionMeta;
import com.alphawallet.app.entity.Wallet;
import com.alphawallet.app.repository.entity.Realm1559Gas;
import com.alphawallet.app.repository.entity.RealmAuxData;
import com.alphawallet.app.repository.entity.RealmNFTAsset;
import com.alphawallet.app.repository.entity.RealmToken;
Expand Down Expand Up @@ -295,6 +296,7 @@ public Single<Boolean> deleteAllForWallet(String currentAddress)
r.where(RealmAuxData.class).findAll().deleteAllFromRealm();
r.where(RealmNFTAsset.class).findAll().deleteAllFromRealm();
r.where(RealmTransfer.class).findAll().deleteAllFromRealm();
r.where(Realm1559Gas.class).findAll().deleteAllFromRealm();
});
instance.refresh();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ public class Realm1559Gas extends RealmObject
public Map<Integer, EIP1559FeeOracleResult> getResult()
{
Type entry = new TypeToken<Map<Integer, EIP1559FeeOracleResult>>() {}.getType();
return new Gson().fromJson(resultData, entry);
return new Gson().fromJson(getResultData(), entry);
}

public String getResultData()
{
return resultData;
}

public void setResultData(Map<Integer, EIP1559FeeOracleResult> result, long ts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@
return requestB.build();
}

public Single<Map<Integer, EIP1559FeeOracleResult>> fetchGasEstimates(long chainId)
public Single<Map<Integer, EIP1559FeeOracleResult>> get1559GasEstimates(Map<Integer, EIP1559FeeOracleResult> result, long chainId)
{
if (result.size() > 0)
{
return Single.fromCallable(() -> result);

Check warning on line 62 in app/src/main/java/com/alphawallet/app/service/BlockNativeGasAPI.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/service/BlockNativeGasAPI.java#L62

Added line #L62 was not covered by tests
}
String oracleAPI = EthereumNetworkBase.getBlockNativeOracle(chainId);
return Single.fromCallable(() -> buildOracleResult(executeRequest(oracleAPI))); // any kind of error results in blank mapping,
// if blank, fall back to calculation method
Expand Down
19 changes: 11 additions & 8 deletions app/src/main/java/com/alphawallet/app/service/GasService.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import com.alphawallet.app.repository.entity.Realm1559Gas;
import com.alphawallet.app.repository.entity.RealmGasSpread;
import com.alphawallet.app.web3.entity.Web3Transaction;
import org.web3j.utils.Numeric;
import com.google.gson.Gson;

import org.jetbrains.annotations.Nullable;
Expand All @@ -41,6 +40,7 @@
import org.web3j.protocol.core.methods.response.EthGasPrice;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.Map;
Expand Down Expand Up @@ -82,6 +82,7 @@
private final String ETHERSCAN_API_KEY;
private final String POLYGONSCAN_API_KEY;
private boolean keyFail;

@Nullable
private Disposable gasFetchDisposable;

Expand Down Expand Up @@ -186,7 +187,7 @@

private Single<Boolean> updateCurrentGasPrices()
{
String gasOracleAPI = EthereumNetworkRepository.getGasOracle(currentChainId);
String gasOracleAPI = EthereumNetworkRepository.getEtherscanGasOracle(currentChainId);

Check warning on line 190 in app/src/main/java/com/alphawallet/app/service/GasService.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/service/GasService.java#L190

Added line #L190 was not covered by tests
if (!TextUtils.isEmpty(gasOracleAPI))
{
if (!keyFail && gasOracleAPI.contains("etherscan")) gasOracleAPI += ETHERSCAN_API_KEY;
Expand Down Expand Up @@ -303,13 +304,14 @@
Realm1559Gas rgs = r.where(Realm1559Gas.class)
.equalTo("chainId", chainId)
.findFirst();

if (rgs == null)
{
rgs = r.createObject(Realm1559Gas.class, chainId);
}

rgs.setResultData(result, System.currentTimeMillis());
r.insertOrUpdate(rgs);
//r.insertOrUpdate(rgs);
});
}
catch (Exception e)
Expand All @@ -325,11 +327,11 @@
{
updateChainId(chainId);
return useNodeEstimate(true)
.flatMap(com -> calculateGasEstimateInternal(transactionBytes, chainId, toAddress, amount, wallet, defaultLimit));
.flatMap(com -> calculateGasEstimateInternal(transactionBytes, chainId, toAddress, amount, wallet, defaultLimit));

Check warning on line 330 in app/src/main/java/com/alphawallet/app/service/GasService.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/service/GasService.java#L330

Added line #L330 was not covered by tests
}

public Single<GasEstimate> calculateGasEstimateInternal(byte[] transactionBytes, long chainId, String toAddress,
BigInteger amount, Wallet wallet, final BigInteger defaultLimit)
BigInteger amount, Wallet wallet, final BigInteger defaultLimit)
{
String txData = "";
if (transactionBytes != null && transactionBytes.length > 0)
Expand Down Expand Up @@ -387,7 +389,7 @@
{
if (!estimate.hasError() || chainId != 1) return Single.fromCallable(() -> estimate);
else return networkRepository.getLastTransactionNonce(web3j, WHALE_ACCOUNT)
.flatMap(nonce -> ethEstimateGas(chainId, WHALE_ACCOUNT, nonce, toAddress, amount, finalTxData));
.flatMap(nonce -> ethEstimateGas(chainId, WHALE_ACCOUNT, nonce, toAddress, amount, finalTxData));

Check warning on line 392 in app/src/main/java/com/alphawallet/app/service/GasService.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/service/GasService.java#L392

Added line #L392 was not covered by tests
}

private BigInteger getLowGasPrice()
Expand Down Expand Up @@ -420,8 +422,9 @@

private Single<Map<Integer, EIP1559FeeOracleResult>> getEIP1559FeeStructure()
{
return BlockNativeGasAPI.get(httpClient).fetchGasEstimates(currentChainId)
.flatMap(this::useCalculationIfRequired); //if interface doesn't have blocknative API then use calculation method
return InfuraGasAPI.get1559GasEstimates(currentChainId, httpClient)
.flatMap(result -> BlockNativeGasAPI.get(httpClient).get1559GasEstimates(result, currentChainId))
.flatMap(this::useCalculationIfRequired); //if interface doesn't have blocknative API then use calculation method

Check warning on line 427 in app/src/main/java/com/alphawallet/app/service/GasService.java

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/alphawallet/app/service/GasService.java#L425-L427

Added lines #L425 - L427 were not covered by tests
}

private Single<Map<Integer, EIP1559FeeOracleResult>> useCalculationIfRequired(Map<Integer, EIP1559FeeOracleResult> resultMap)
Expand Down
Loading
Loading