mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-22 09:18:05 +01:00
Add CoinGecko to CurrencyConversionManager
This commit is contained in:
@@ -10,7 +10,7 @@ import java.math.BigDecimal;
|
||||
import java.net.http.HttpClient;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.whispersystems.textsecuregcm.currency.CoinMarketCapClient;
|
||||
import org.whispersystems.textsecuregcm.currency.CoinGeckoClient;
|
||||
import org.whispersystems.textsecuregcm.currency.FixerClient;
|
||||
|
||||
@JsonTypeName("stub")
|
||||
@@ -22,8 +22,8 @@ public class StubPaymentsServiceClientsFactory implements PaymentsServiceClients
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoinMarketCapClient buildCoinMarketCapClient(final HttpClient httpClient) {
|
||||
return new StubCoinMarketCapClient();
|
||||
public CoinGeckoClient buildCoinGeckoClient(final HttpClient httpClient) {
|
||||
return new StubCoinGeckoClient();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,9 +44,9 @@ public class StubPaymentsServiceClientsFactory implements PaymentsServiceClients
|
||||
/**
|
||||
* Always returns {@code 0} for spot price checks
|
||||
*/
|
||||
private static class StubCoinMarketCapClient extends CoinMarketCapClient {
|
||||
private static class StubCoinGeckoClient extends CoinGeckoClient {
|
||||
|
||||
public StubCoinMarketCapClient() {
|
||||
public StubCoinGeckoClient() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.whispersystems.textsecuregcm.currency;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CoinGeckoClientTest {
|
||||
|
||||
private static final String RESPONSE_JSON = """
|
||||
{
|
||||
"mobilecoin": {
|
||||
"usd": 0.226212
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
void parseResponse() throws JsonProcessingException {
|
||||
final Map<String, Map<String, BigDecimal>> parsedResponse = CoinGeckoClient.parseResponse(RESPONSE_JSON);
|
||||
|
||||
assertTrue(parsedResponse.containsKey("mobilecoin"));
|
||||
|
||||
assertEquals(1, parsedResponse.get("mobilecoin").size());
|
||||
assertEquals(new BigDecimal("0.226212"), parsedResponse.get("mobilecoin").get("usd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void extractConversionRate() throws IOException {
|
||||
final Map<String, Map<String, BigDecimal>> parsedResponse = CoinGeckoClient.parseResponse(RESPONSE_JSON);
|
||||
|
||||
assertEquals(new BigDecimal("0.226212"), CoinGeckoClient.extractConversionRate(parsedResponse.get("mobilecoin"), "usd"));
|
||||
assertThrows(IOException.class, () -> CoinGeckoClient.extractConversionRate(parsedResponse.get("mobilecoin"), "CAD"));
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package org.whispersystems.textsecuregcm.currency;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CoinMarketCapClientTest {
|
||||
|
||||
private static final String RESPONSE_JSON = """
|
||||
{
|
||||
"status": {
|
||||
"timestamp": "2022-11-09T17:15:06.356Z",
|
||||
"error_code": 0,
|
||||
"error_message": null,
|
||||
"elapsed": 41,
|
||||
"credit_count": 1,
|
||||
"notice": null
|
||||
},
|
||||
"data": {
|
||||
"id": 7878,
|
||||
"symbol": "MOB",
|
||||
"name": "MobileCoin",
|
||||
"amount": 1,
|
||||
"last_updated": "2022-11-09T17:14:00.000Z",
|
||||
"quote": {
|
||||
"USD": {
|
||||
"price": 0.6625319895827952,
|
||||
"last_updated": "2022-11-09T17:14:00.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
void parseResponse() throws JsonProcessingException {
|
||||
final CoinMarketCapClient.CoinMarketCapResponse parsedResponse = CoinMarketCapClient.parseResponse(RESPONSE_JSON);
|
||||
|
||||
assertEquals(7878, parsedResponse.priceConversionResponse().id());
|
||||
assertEquals("MOB", parsedResponse.priceConversionResponse().symbol());
|
||||
|
||||
final Map<String, CoinMarketCapClient.PriceConversionQuote> quote =
|
||||
parsedResponse.priceConversionResponse().quote();
|
||||
|
||||
assertEquals(1, quote.size());
|
||||
assertEquals(new BigDecimal("0.6625319895827952"), quote.get("USD").price());
|
||||
}
|
||||
|
||||
@Test
|
||||
void extractConversionRate() throws IOException {
|
||||
final CoinMarketCapClient.CoinMarketCapResponse parsedResponse = CoinMarketCapClient.parseResponse(RESPONSE_JSON);
|
||||
|
||||
assertEquals(new BigDecimal("0.6625319895827952"), CoinMarketCapClient.extractConversionRate(parsedResponse, "USD"));
|
||||
assertThrows(IOException.class, () -> CoinMarketCapClient.extractConversionRate(parsedResponse, "CAD"));
|
||||
}
|
||||
}
|
||||
@@ -38,16 +38,16 @@ class CurrencyConversionManagerTest {
|
||||
@Test
|
||||
void testCurrencyCalculations() throws IOException {
|
||||
FixerClient fixerClient = mock(FixerClient.class);
|
||||
CoinMarketCapClient coinMarketCapClient = mock(CoinMarketCapClient.class);
|
||||
CoinGeckoClient coinGeckoClient = mock(CoinGeckoClient.class);
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(coinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("0.822876"),
|
||||
"FJD", new BigDecimal("2.0577"),
|
||||
"FKP", new BigDecimal("0.743446")
|
||||
));
|
||||
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinMarketCapClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinGeckoClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
List.of("FOO"), EXECUTOR, Clock.systemUTC());
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
@@ -66,9 +66,9 @@ class CurrencyConversionManagerTest {
|
||||
@Test
|
||||
void testCurrencyCalculations_noTrailingZeros() throws IOException {
|
||||
FixerClient fixerClient = mock(FixerClient.class);
|
||||
CoinMarketCapClient coinMarketCapClient = mock(CoinMarketCapClient.class);
|
||||
CoinGeckoClient CoinGeckoClient = mock(CoinGeckoClient.class);
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("1.00000"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("1.00000"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("0.200000"),
|
||||
"FJD", new BigDecimal("3.00000"),
|
||||
@@ -76,7 +76,7 @@ class CurrencyConversionManagerTest {
|
||||
"CAD", new BigDecimal("700.000")
|
||||
));
|
||||
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinMarketCapClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, CoinGeckoClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
List.of("FOO"), EXECUTOR, Clock.systemUTC());
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
@@ -96,16 +96,16 @@ class CurrencyConversionManagerTest {
|
||||
@Test
|
||||
void testCurrencyCalculations_accuracy() throws IOException {
|
||||
FixerClient fixerClient = mock(FixerClient.class);
|
||||
CoinMarketCapClient coinMarketCapClient = mock(CoinMarketCapClient.class);
|
||||
CoinGeckoClient CoinGeckoClient = mock(CoinGeckoClient.class);
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("0.999999"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("0.999999"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("1.000001"),
|
||||
"FJD", new BigDecimal("0.000001"),
|
||||
"FKP", new BigDecimal("1")
|
||||
));
|
||||
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinMarketCapClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, CoinGeckoClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
List.of("FOO"), EXECUTOR, Clock.systemUTC());
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
@@ -125,21 +125,21 @@ class CurrencyConversionManagerTest {
|
||||
@Test
|
||||
void testCurrencyCalculationsTimeoutNoRun() throws IOException {
|
||||
FixerClient fixerClient = mock(FixerClient.class);
|
||||
CoinMarketCapClient coinMarketCapClient = mock(CoinMarketCapClient.class);
|
||||
CoinGeckoClient CoinGeckoClient = mock(CoinGeckoClient.class);
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("0.822876"),
|
||||
"FJD", new BigDecimal("2.0577"),
|
||||
"FKP", new BigDecimal("0.743446")
|
||||
));
|
||||
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinMarketCapClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, CoinGeckoClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
List.of("FOO"), EXECUTOR, Clock.systemUTC());
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("3.50"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("3.50"));
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
|
||||
@@ -155,26 +155,26 @@ class CurrencyConversionManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCurrencyCalculationsCoinMarketCapTimeoutWithRun() throws IOException {
|
||||
void testCurrencyCalculationsCoinGeckoTimeoutWithRun() throws IOException {
|
||||
FixerClient fixerClient = mock(FixerClient.class);
|
||||
CoinMarketCapClient coinMarketCapClient = mock(CoinMarketCapClient.class);
|
||||
CoinGeckoClient CoinGeckoClient = mock(CoinGeckoClient.class);
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("0.822876"),
|
||||
"FJD", new BigDecimal("2.0577"),
|
||||
"FKP", new BigDecimal("0.743446")
|
||||
));
|
||||
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinMarketCapClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, CoinGeckoClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
List.of("FOO"), EXECUTOR, Clock.systemUTC());
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster().useCluster(connection ->
|
||||
connection.sync().del(CurrencyConversionManager.COIN_MARKET_CAP_SHARED_CACHE_CURRENT_KEY));
|
||||
connection.sync().del(CurrencyConversionManager.COIN_GECKO_CAP_SHARED_CACHE_CURRENT_KEY));
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("3.50"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("3.50"));
|
||||
manager.updateCacheIfNecessary();
|
||||
|
||||
CurrencyConversionEntityList conversions = manager.getCurrencyConversions().orElseThrow();
|
||||
@@ -192,9 +192,9 @@ class CurrencyConversionManagerTest {
|
||||
@Test
|
||||
void testCurrencyCalculationsFixerTimeoutWithRun() throws IOException {
|
||||
FixerClient fixerClient = mock(FixerClient.class);
|
||||
CoinMarketCapClient coinMarketCapClient = mock(CoinMarketCapClient.class);
|
||||
CoinGeckoClient CoinGeckoClient = mock(CoinGeckoClient.class);
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("2.35"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("0.822876"),
|
||||
"FJD", new BigDecimal("2.0577"),
|
||||
@@ -207,12 +207,12 @@ class CurrencyConversionManagerTest {
|
||||
when(clock.instant()).thenReturn(currentTime);
|
||||
when(clock.millis()).thenReturn(currentTime.toEpochMilli());
|
||||
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, coinMarketCapClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
CurrencyConversionManager manager = new CurrencyConversionManager(fixerClient, CoinGeckoClient, REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
List.of("FOO"), EXECUTOR, clock);
|
||||
|
||||
manager.updateCacheIfNecessary();
|
||||
|
||||
when(coinMarketCapClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("3.50"));
|
||||
when(CoinGeckoClient.getSpotPrice(eq("FOO"), eq("USD"))).thenReturn(new BigDecimal("3.50"));
|
||||
when(fixerClient.getConversionsForBase(eq("USD"))).thenReturn(Map.of(
|
||||
"EUR", new BigDecimal("0.922876"),
|
||||
"FJD", new BigDecimal("2.0577"),
|
||||
@@ -239,7 +239,7 @@ class CurrencyConversionManagerTest {
|
||||
@Test
|
||||
void convertToUsd() {
|
||||
final CurrencyConversionManager currencyConversionManager = new CurrencyConversionManager(mock(FixerClient.class),
|
||||
mock(CoinMarketCapClient.class),
|
||||
mock(CoinGeckoClient.class),
|
||||
mock(FaultTolerantRedisClusterClient.class),
|
||||
Collections.emptyList(),
|
||||
EXECUTOR,
|
||||
|
||||
Reference in New Issue
Block a user