Refactor gas handling and fix some issues (#3272)
parent
730448cd27
commit
ed094eb78b
@ -0,0 +1,166 @@ |
||||
package com.alphawallet.app.service; |
||||
|
||||
import android.text.TextUtils; |
||||
|
||||
import com.alphawallet.app.entity.EIP1559FeeOracleResult; |
||||
import com.alphawallet.app.repository.EthereumNetworkBase; |
||||
import com.alphawallet.app.repository.KeyProviderFactory; |
||||
import com.alphawallet.app.util.BalanceUtils; |
||||
import com.alphawallet.app.util.JsonUtils; |
||||
import com.google.gson.Gson; |
||||
|
||||
import org.json.JSONArray; |
||||
import org.json.JSONException; |
||||
import org.json.JSONObject; |
||||
|
||||
import java.io.IOException; |
||||
import java.math.BigDecimal; |
||||
import java.math.BigInteger; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
import io.reactivex.Single; |
||||
import okhttp3.OkHttpClient; |
||||
import okhttp3.Request; |
||||
import okhttp3.ResponseBody; |
||||
import timber.log.Timber; |
||||
|
||||
public class BlockNativeGasAPI |
||||
{ |
||||
public static BlockNativeGasAPI instance; |
||||
private final OkHttpClient httpClient; |
||||
|
||||
public static BlockNativeGasAPI get(OkHttpClient httpClient) |
||||
{ |
||||
if (instance == null) |
||||
{ |
||||
instance = new BlockNativeGasAPI(httpClient); |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
public BlockNativeGasAPI(OkHttpClient httpClient) |
||||
{ |
||||
this.httpClient = httpClient; |
||||
} |
||||
|
||||
private Request buildRequest(String api) |
||||
{ |
||||
Request.Builder requestB = new Request.Builder() |
||||
.url(api) |
||||
.header("Content-Type", "application/json") |
||||
.addHeader("Authorization", KeyProviderFactory.get().getBlockNativeKey()) |
||||
.get(); |
||||
return requestB.build(); |
||||
} |
||||
|
||||
public Single<Map<Integer, EIP1559FeeOracleResult>> fetchGasEstimates(long chainId) |
||||
{ |
||||
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
|
||||
} |
||||
|
||||
private Map<Integer, EIP1559FeeOracleResult> buildOracleResult(String oracleReturn) |
||||
{ |
||||
Map<Integer, EIP1559FeeOracleResult> results = new HashMap<>(); |
||||
try |
||||
{ |
||||
JSONObject prices = new JSONObject(oracleReturn); |
||||
//get base fee per gas
|
||||
JSONArray blockPrices = prices.getJSONArray("blockPrices"); |
||||
JSONObject blockPrice0 = blockPrices.getJSONObject(0); |
||||
String baseFeePerGasStr = blockPrice0.getString("baseFeePerGas"); |
||||
BigDecimal baseFeePerGas = new BigDecimal(baseFeePerGasStr); |
||||
BigInteger baseFeePerGasWei = BalanceUtils.gweiToWei(baseFeePerGas); |
||||
//get the array
|
||||
String estimatedPrices = blockPrice0.getJSONArray("estimatedPrices").toString(); |
||||
PriceElement[] priceElements = new Gson().fromJson(estimatedPrices, PriceElement[].class); |
||||
|
||||
results.put(0, new EIP1559FeeOracleResult(priceElements[0].getFeeOracleResult(baseFeePerGasWei))); |
||||
results.put(1, new EIP1559FeeOracleResult(priceElements[2].getFeeOracleResult(baseFeePerGasWei))); |
||||
results.put(2, new EIP1559FeeOracleResult(priceElements[3].getFeeOracleResult(baseFeePerGasWei))); |
||||
results.put(3, new EIP1559FeeOracleResult(priceElements[4].getFeeOracleResult(baseFeePerGasWei))); |
||||
} |
||||
catch (JSONException e) |
||||
{ |
||||
// map will be empty; default to using backup calculation method
|
||||
Timber.w(e); |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
private String executeRequest(String api) |
||||
{ |
||||
if (!TextUtils.isEmpty(api)) |
||||
{ |
||||
try (okhttp3.Response response = httpClient.newCall(buildRequest(api)).execute()) |
||||
{ |
||||
if (response.isSuccessful()) |
||||
{ |
||||
ResponseBody responseBody = response.body(); |
||||
if (responseBody != null) |
||||
{ |
||||
return responseBody.string(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return Objects.requireNonNull(response.body()).string(); |
||||
} |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
Timber.e(e); |
||||
return e.getMessage(); |
||||
} |
||||
} |
||||
|
||||
return JsonUtils.EMPTY_RESULT; |
||||
} |
||||
|
||||
private static class PriceElement |
||||
{ |
||||
public String confidence; |
||||
public String price; |
||||
public String maxPriorityFeePerGas; |
||||
public String maxFeePerGas; |
||||
|
||||
public BigInteger getMaxPriorityFeePerGasWei() |
||||
{ |
||||
return elementToWei(maxPriorityFeePerGas); |
||||
} |
||||
|
||||
public BigInteger getMaxFeePerGasWei() |
||||
{ |
||||
return elementToWei(maxFeePerGas); |
||||
} |
||||
|
||||
private BigInteger elementToWei(String value) |
||||
{ |
||||
try |
||||
{ |
||||
BigDecimal gweiValue = new BigDecimal(value); |
||||
return BalanceUtils.gweiToWei(gweiValue); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
return BigInteger.ZERO; |
||||
} |
||||
} |
||||
|
||||
/* |
||||
public EIP1559FeeOracleResult(BigInteger maxFee, BigInteger maxPriority, BigInteger base) |
||||
{ |
||||
maxFeePerGas = fixGasPriceReturn(maxFee); // Some chains (eg Phi) have a gas price lower than 1Gwei.
|
||||
maxPriorityFeePerGas = fixGasPriceReturn(maxPriority); |
||||
baseFee = base; |
||||
} |
||||
*/ |
||||
public EIP1559FeeOracleResult getFeeOracleResult(BigInteger baseFee) |
||||
{ |
||||
return new EIP1559FeeOracleResult(getMaxFeePerGasWei(), getMaxPriorityFeePerGasWei(), baseFee); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,91 @@ |
||||
package com.alphawallet.app.ui.widget.entity; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
import com.alphawallet.app.entity.EIP1559FeeOracleResult; |
||||
import com.alphawallet.app.util.BalanceUtils; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.math.BigInteger; |
||||
|
||||
/** |
||||
* Created by JB on 20/01/2022. |
||||
*/ |
||||
public class GasSpeed implements Parcelable |
||||
{ |
||||
public final String speed; |
||||
public long seconds; |
||||
public final EIP1559FeeOracleResult gasPrice; |
||||
|
||||
public GasSpeed(String speed, long seconds, EIP1559FeeOracleResult gasPrice) |
||||
{ |
||||
this.speed = speed; |
||||
this.seconds = seconds; |
||||
this.gasPrice = gasPrice; |
||||
} |
||||
|
||||
public GasSpeed(Parcel in) |
||||
{ |
||||
speed = in.readString(); |
||||
seconds = in.readLong(); |
||||
gasPrice = in.readParcelable(EIP1559FeeOracleResult.class.getClassLoader()); |
||||
} |
||||
|
||||
public GasSpeed(String speed, long seconds, BigInteger gasPrice) |
||||
{ |
||||
this.speed = speed; |
||||
this.seconds = seconds; |
||||
this.gasPrice = new EIP1559FeeOracleResult(gasPrice, BigInteger.ZERO, BigInteger.ZERO); |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel dest, int flags) |
||||
{ |
||||
dest.writeString(speed); |
||||
dest.writeLong(seconds); |
||||
dest.writeParcelable(gasPrice, flags); |
||||
} |
||||
|
||||
public static final Creator<GasSpeed> CREATOR = new Creator<GasSpeed>() { |
||||
@Override |
||||
public GasSpeed createFromParcel(Parcel in) { |
||||
return new GasSpeed(in); |
||||
} |
||||
|
||||
@Override |
||||
public GasSpeed[] newArray(int size) { |
||||
return new GasSpeed[size]; |
||||
} |
||||
}; |
||||
|
||||
public BigDecimal calculateGasFee(BigDecimal useGasLimit, boolean isUsing1559) |
||||
{ |
||||
if (isUsing1559) |
||||
{ |
||||
return new BigDecimal(gasPrice.baseFee.add(gasPrice.priorityFee)).multiply(useGasLimit); |
||||
} |
||||
else |
||||
{ |
||||
return new BigDecimal(gasPrice.maxFeePerGas).multiply(useGasLimit); |
||||
} |
||||
} |
||||
|
||||
public BigDecimal calculateMaxGasFee(BigDecimal useGasLimit) |
||||
{ |
||||
if (gasPrice.maxFeePerGas != null && gasPrice.maxFeePerGas.compareTo(BigInteger.ZERO) > 0) |
||||
{ |
||||
return new BigDecimal(gasPrice.maxFeePerGas).multiply(useGasLimit); |
||||
} |
||||
else |
||||
{ |
||||
return BigDecimal.ZERO; |
||||
} |
||||
} |
||||
} |
@ -1,65 +0,0 @@ |
||||
package com.alphawallet.app.ui.widget.entity; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
import com.alphawallet.app.entity.EIP1559FeeOracleResult; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
/** |
||||
* Created by JB on 20/01/2022. |
||||
*/ |
||||
public class GasSpeed2 implements Parcelable |
||||
{ |
||||
public final String speed; |
||||
public long seconds; |
||||
public final EIP1559FeeOracleResult gasPrice; |
||||
|
||||
public GasSpeed2(String speed, long seconds, EIP1559FeeOracleResult gasPrice) |
||||
{ |
||||
this.speed = speed; |
||||
this.seconds = seconds; |
||||
this.gasPrice = gasPrice; |
||||
} |
||||
|
||||
public GasSpeed2(Parcel in) |
||||
{ |
||||
speed = in.readString(); |
||||
seconds = in.readLong(); |
||||
gasPrice = in.readParcelable(EIP1559FeeOracleResult.class.getClassLoader()); |
||||
} |
||||
|
||||
public GasSpeed2(String speed, long seconds, BigInteger gasPrice) |
||||
{ |
||||
this.speed = speed; |
||||
this.seconds = seconds; |
||||
this.gasPrice = new EIP1559FeeOracleResult(gasPrice, BigInteger.ZERO, BigInteger.ZERO); |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel dest, int flags) |
||||
{ |
||||
dest.writeString(speed); |
||||
dest.writeLong(seconds); |
||||
dest.writeParcelable(gasPrice, flags); |
||||
} |
||||
|
||||
public static final Creator<GasSpeed2> CREATOR = new Creator<GasSpeed2>() { |
||||
@Override |
||||
public GasSpeed2 createFromParcel(Parcel in) { |
||||
return new GasSpeed2(in); |
||||
} |
||||
|
||||
@Override |
||||
public GasSpeed2[] newArray(int size) { |
||||
return new GasSpeed2[size]; |
||||
} |
||||
}; |
||||
} |
Loading…
Reference in new issue