Use BigDecimal instead of Double for currency rate calculations (#134)

use BigDecimal instead of double for accuracy
This commit is contained in:
Sophiah Ho
2021-09-10 17:15:57 -04:00
committed by GitHub
parent 489519a982
commit feb59deb28
10 changed files with 251 additions and 53 deletions

View File

@@ -8,6 +8,7 @@ import org.whispersystems.textsecuregcm.entities.CurrencyConversionEntityList;
import org.whispersystems.textsecuregcm.util.Util;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -34,8 +35,8 @@ public class CurrencyConversionManager implements Managed {
private long fixerUpdatedTimestamp;
private long ftxUpdatedTimestamp;
private Map<String, Double> cachedFixerValues;
private Map<String, Double> cachedFtxValues;
private Map<String, BigDecimal> cachedFixerValues;
private Map<String, BigDecimal> cachedFtxValues;
public CurrencyConversionManager(FixerClient fixerClient, FtxClient ftxClient, List<String> currencies) {
this.fixerClient = fixerClient;
@@ -75,7 +76,7 @@ public class CurrencyConversionManager implements Managed {
}
if (System.currentTimeMillis() - ftxUpdatedTimestamp > FTX_INTERVAL || cachedFtxValues == null) {
Map<String, Double> cachedFtxValues = new HashMap<>();
Map<String, BigDecimal> cachedFtxValues = new HashMap<>();
for (String currency : currencies) {
cachedFtxValues.put(currency, ftxClient.getSpotPrice(currency, "USD"));
@@ -87,14 +88,14 @@ public class CurrencyConversionManager implements Managed {
List<CurrencyConversionEntity> entities = new LinkedList<>();
for (Map.Entry<String, Double> currency : cachedFtxValues.entrySet()) {
double usdValue = currency.getValue();
for (Map.Entry<String, BigDecimal> currency : cachedFtxValues.entrySet()) {
BigDecimal usdValue = stripTrailingZerosAfterDecimal(currency.getValue());
Map<String, Double> values = new HashMap<>();
Map<String, BigDecimal> values = new HashMap<>();
values.put("USD", usdValue);
for (Map.Entry<String, Double> conversion : cachedFixerValues.entrySet()) {
values.put(conversion.getKey(), conversion.getValue() * usdValue);
for (Map.Entry<String, BigDecimal> conversion : cachedFixerValues.entrySet()) {
values.put(conversion.getKey(), stripTrailingZerosAfterDecimal(conversion.getValue().multiply(usdValue)));
}
entities.add(new CurrencyConversionEntity(currency.getKey(), values));
@@ -104,6 +105,15 @@ public class CurrencyConversionManager implements Managed {
this.cached.set(new CurrencyConversionEntityList(entities, ftxUpdatedTimestamp));
}
private BigDecimal stripTrailingZerosAfterDecimal(BigDecimal bigDecimal) {
BigDecimal n = bigDecimal.stripTrailingZeros();
if (n.scale() < 0) {
return n.setScale(0);
} else {
return n;
}
}
@VisibleForTesting
void setFixerUpdatedTimestamp(long timestamp) {
this.fixerUpdatedTimestamp = timestamp;

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
@@ -20,7 +21,7 @@ public class FixerClient {
this.client = client;
}
public Map<String, Double> getConversionsForBase(String base) throws FixerException {
public Map<String, BigDecimal> getConversionsForBase(String base) throws FixerException {
try {
URI uri = URI.create("https://data.fixer.io/api/latest?access_key=" + apiKey + "&base=" + base);
@@ -58,7 +59,7 @@ public class FixerClient {
private String date;
@JsonProperty
private Map<String, Double> rates;
private Map<String, BigDecimal> rates;
}

View File

@@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
@@ -18,7 +19,7 @@ public class FtxClient {
this.client = client;
}
public double getSpotPrice(String currency, String base) throws FtxException{
public BigDecimal getSpotPrice(String currency, String base) throws FtxException{
try {
URI uri = URI.create("https://ftx.com/api/markets/" + currency + "/" + base);
@@ -51,7 +52,7 @@ public class FtxClient {
private static class FtxResult {
@JsonProperty
private double price;
private BigDecimal price;
}