From b8d6bbacbf60b5d8cda02882ba19661e2fb5e693 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 5 Feb 2024 15:35:32 +0100 Subject: [PATCH 01/14] Implemented conversion methods in CCDAmount, Energy and created EuroAmount --- .../sdk/requests/smartcontracts/Energy.java | 23 ++++++++++ .../chainparameters/ChainParameters.java | 5 +++ .../chainparameters/ChainParametersV1.java | 6 +-- .../sdk/transactions/CCDAmount.java | 14 +++++- .../sdk/transactions/EuroAmount.java | 44 +++++++++++++++++++ 5 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java index 9673b8c07..0ffff6fb6 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java @@ -1,5 +1,8 @@ package com.concordium.sdk.requests.smartcontracts; +import com.concordium.sdk.responses.chainparameters.ChainParameters; +import com.concordium.sdk.transactions.CCDAmount; +import com.concordium.sdk.transactions.EuroAmount; import com.concordium.sdk.types.UInt64; import lombok.Builder; import lombok.EqualsAndHashCode; @@ -26,4 +29,24 @@ public static Energy from(com.concordium.grpc.v2.Energy energy) { public static Energy from(UInt64 value) { return new Energy(value); } + + /** + * Approximates the {@link EuroAmount} amount corresponding to the {@link Energy} using the provided {@link ChainParameters}. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link EuroAmount} corresponding to the value of {@link Energy} + */ + public EuroAmount toEuro(ChainParameters parameters) { + double euroPerEnergy = parameters.getEuroPerEnergy().asDouble(); + double euros = value.getValue() * euroPerEnergy; + return EuroAmount.from(euros); + } + + /** + * Approximates the {@link CCDAmount} corresponding to the {@link Energy} using the provided {@link ChainParameters}. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link CCDAmount} corresponding to the value of {@link Energy}. + */ + public CCDAmount toCCD(ChainParameters parameters) { + return this.toEuro(parameters).toCCD(parameters); + } } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParameters.java b/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParameters.java index dfbaf0f08..13dc6fa3e 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParameters.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParameters.java @@ -1,5 +1,7 @@ package com.concordium.sdk.responses.chainparameters; +import com.concordium.sdk.responses.Fraction; + /** * Base class for all chain parameters. * All chain parameters must implement 'getVersion'. @@ -8,6 +10,9 @@ public abstract class ChainParameters { public abstract Version getVersion(); + public abstract Fraction getEuroPerEnergy(); + public abstract Fraction getMicroCCDPerEuro(); + /** * Chain parameters versions */ diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParametersV1.java b/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParametersV1.java index 737efa283..869a02500 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParametersV1.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/responses/chainparameters/ChainParametersV1.java @@ -5,10 +5,7 @@ import com.concordium.sdk.responses.transactionstatus.PartsPerHundredThousand; import com.concordium.sdk.transactions.CCDAmount; import com.concordium.sdk.types.AccountAddress; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import lombok.*; /** * Chain parameters for protocol versions 4 to 5. @@ -16,6 +13,7 @@ @ToString @EqualsAndHashCode(callSuper = false) @Builder +@Getter @AllArgsConstructor public class ChainParametersV1 extends ChainParameters { diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java index d1212485e..de42246e7 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java @@ -1,6 +1,9 @@ package com.concordium.sdk.transactions; import com.concordium.grpc.v2.Amount; +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.responses.Fraction; +import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.types.UInt64; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; @@ -8,7 +11,6 @@ import lombok.Getter; import java.nio.ByteBuffer; -import java.text.DecimalFormat; /** * A CCD amount with 'micro' precision. @@ -63,6 +65,16 @@ public static CCDAmount fromBytes(ByteBuffer source) { return new CCDAmount(value); } + public EuroAmount toEuro(ChainParameters parameters) { + double microCCDPerEuro = parameters.getMicroCCDPerEuro().asDouble(); + Fraction flipped = Fraction.from(parameters.getMicroCCDPerEuro().getDenominator().getValue(), parameters.getMicroCCDPerEuro().getNumerator().getValue()); + return EuroAmount.from(this.getValue().getValue() / microCCDPerEuro); + } + + public Energy toEnergy(ChainParameters parameters) { + return this.toEuro(parameters).toEnergy(parameters); + } + @Override public String toString() { return this.getValue().toString() + " micro CCD"; diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java new file mode 100644 index 000000000..7f0734126 --- /dev/null +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java @@ -0,0 +1,44 @@ +package com.concordium.sdk.transactions; + + +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.responses.Fraction; +import com.concordium.sdk.responses.chainparameters.ChainParameters; +import com.concordium.sdk.types.UInt64; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +/** + * An amount of Euros. + */ +@Getter +@EqualsAndHashCode +public class EuroAmount { + + private final double value; + + private EuroAmount(double value) { + this.value = value; + } + + public static EuroAmount from(double value) { + return new EuroAmount(value); + } + + public Energy toEnergy(ChainParameters parameters) { + double euroPerEnergy = parameters.getEuroPerEnergy().asDouble(); + Fraction flipped = Fraction.from(parameters.getEuroPerEnergy().getDenominator().getValue(), parameters.getEuroPerEnergy().getNumerator().getValue()); + return Energy.from(UInt64.from((long) (this.getValue() / euroPerEnergy))); + + } + + public CCDAmount toCCD(ChainParameters parameters) { + double microCCDPerEuro = parameters.getMicroCCDPerEuro().asDouble(); + return CCDAmount.fromMicro((long) (this.getValue() * microCCDPerEuro)); + } + + @Override + public String toString() { + return this.getValue() + " Euros"; + } +} From 8c4739714f8c0dc6dc71314b724326496c8e9a1d Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 12 Feb 2024 13:48:45 +0100 Subject: [PATCH 02/14] Refactored to use BigDecimal to avoid overflow when microCCD/Euro is very large --- .../sdk/requests/smartcontracts/Energy.java | 14 ++++++++++---- .../com/concordium/sdk/responses/Fraction.java | 16 ++++++++++++++++ .../concordium/sdk/transactions/CCDAmount.java | 10 ++++++---- .../sdk/transactions/EuroAmount.java | 18 ++++++++++++------ 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java index 0ffff6fb6..2caa9fe57 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java @@ -8,6 +8,8 @@ import lombok.EqualsAndHashCode; import lombok.Getter; +import java.math.BigDecimal; + /** * Represents energy, i.e. the cost of executing transactions on the chain. */ @@ -19,7 +21,7 @@ public class Energy { @Override public String toString() { - return this.value.getValue() + " NRG"; + return this.value.toString() + " NRG"; } public static Energy from(com.concordium.grpc.v2.Energy energy) { @@ -29,6 +31,9 @@ public static Energy from(com.concordium.grpc.v2.Energy energy) { public static Energy from(UInt64 value) { return new Energy(value); } + public static Energy from(String val) { + return Energy.from(UInt64.from(val)); + } /** * Approximates the {@link EuroAmount} amount corresponding to the {@link Energy} using the provided {@link ChainParameters}. @@ -36,9 +41,10 @@ public static Energy from(UInt64 value) { * @return {@link EuroAmount} corresponding to the value of {@link Energy} */ public EuroAmount toEuro(ChainParameters parameters) { - double euroPerEnergy = parameters.getEuroPerEnergy().asDouble(); - double euros = value.getValue() * euroPerEnergy; - return EuroAmount.from(euros); + BigDecimal euroPerEnergy = parameters.getEuroPerEnergy().asBigDecimal(20); + BigDecimal energy = new BigDecimal(this.getValue().toString()); + BigDecimal euros = energy.multiply(euroPerEnergy); + return EuroAmount.from(euros.toString()); } /** diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java index 708ee9f67..12d6150a7 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java @@ -6,6 +6,9 @@ import lombok.EqualsAndHashCode; import lombok.Getter; +import java.math.BigDecimal; +import java.math.RoundingMode; + /** * A fraction */ @@ -54,4 +57,17 @@ public String toString() { public double asDouble() { return (double) this.numerator.getValue() / (double) this.denominator.getValue(); } + + /** + * Get the fraction as a {@link BigDecimal} value with the specified amount of digits after the decimal point. + * Last decimal is rounded using {@link RoundingMode#HALF_UP} + * + * @param precision how many decimals of precision. + * @return the fraction represented as a {@link BigDecimal}. + */ + public BigDecimal asBigDecimal(int precision) { + BigDecimal numerator = new BigDecimal(this.numerator.toString()); + BigDecimal denominator = new BigDecimal(this.denominator.toString()); + return numerator.divide(denominator, precision, RoundingMode.HALF_UP); + } } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java index de42246e7..89edd8fcd 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java @@ -2,7 +2,6 @@ import com.concordium.grpc.v2.Amount; import com.concordium.sdk.requests.smartcontracts.Energy; -import com.concordium.sdk.responses.Fraction; import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.types.UInt64; import com.fasterxml.jackson.annotation.JsonCreator; @@ -10,6 +9,8 @@ import lombok.EqualsAndHashCode; import lombok.Getter; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.nio.ByteBuffer; /** @@ -66,9 +67,10 @@ public static CCDAmount fromBytes(ByteBuffer source) { } public EuroAmount toEuro(ChainParameters parameters) { - double microCCDPerEuro = parameters.getMicroCCDPerEuro().asDouble(); - Fraction flipped = Fraction.from(parameters.getMicroCCDPerEuro().getDenominator().getValue(), parameters.getMicroCCDPerEuro().getNumerator().getValue()); - return EuroAmount.from(this.getValue().getValue() / microCCDPerEuro); + BigDecimal microCCDPerEuro = parameters.getMicroCCDPerEuro().asBigDecimal(20); + BigDecimal ccd = new BigDecimal(this.getValue().toString()); + BigDecimal euros = ccd.divide(microCCDPerEuro, 20, RoundingMode.HALF_UP); + return EuroAmount.from(euros.toString()); } public Energy toEnergy(ChainParameters parameters) { diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java index 7f0734126..45cd57f31 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java @@ -2,12 +2,14 @@ import com.concordium.sdk.requests.smartcontracts.Energy; -import com.concordium.sdk.responses.Fraction; import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.types.UInt64; import lombok.EqualsAndHashCode; import lombok.Getter; +import java.math.BigDecimal; +import java.math.RoundingMode; + /** * An amount of Euros. */ @@ -24,17 +26,21 @@ private EuroAmount(double value) { public static EuroAmount from(double value) { return new EuroAmount(value); } + public static EuroAmount from(String value) {return EuroAmount.from(Double.parseDouble(value));} public Energy toEnergy(ChainParameters parameters) { - double euroPerEnergy = parameters.getEuroPerEnergy().asDouble(); - Fraction flipped = Fraction.from(parameters.getEuroPerEnergy().getDenominator().getValue(), parameters.getEuroPerEnergy().getNumerator().getValue()); - return Energy.from(UInt64.from((long) (this.getValue() / euroPerEnergy))); + BigDecimal euroPerEnergy = parameters.getEuroPerEnergy().asBigDecimal(20); + BigDecimal euroAmount = BigDecimal.valueOf(this.getValue()); + BigDecimal energy = euroAmount.divide(euroPerEnergy, 20, RoundingMode.HALF_UP); + return Energy.from(UInt64.from(energy.longValue())); } public CCDAmount toCCD(ChainParameters parameters) { - double microCCDPerEuro = parameters.getMicroCCDPerEuro().asDouble(); - return CCDAmount.fromMicro((long) (this.getValue() * microCCDPerEuro)); + BigDecimal microCCDPerEuro = parameters.getMicroCCDPerEuro().asBigDecimal(20); + BigDecimal euroAmount = BigDecimal.valueOf(this.getValue()); + BigDecimal ccd = euroAmount.multiply(microCCDPerEuro); + return CCDAmount.fromMicro(ccd.longValue()); } @Override From a43bdbd9c8c696378ca7723165fe78f0aa76cf95 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 12 Feb 2024 13:58:42 +0100 Subject: [PATCH 03/14] Added documentation --- .../sdk/requests/smartcontracts/Energy.java | 6 ++++-- .../java/com/concordium/sdk/responses/Fraction.java | 4 ++-- .../com/concordium/sdk/transactions/CCDAmount.java | 12 ++++++++++++ .../com/concordium/sdk/transactions/EuroAmount.java | 12 ++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java index 2caa9fe57..7f98e5e48 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java @@ -37,8 +37,9 @@ public static Energy from(String val) { /** * Approximates the {@link EuroAmount} amount corresponding to the {@link Energy} using the provided {@link ChainParameters}. + * Rounding may occur, so result might not be exact. * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link EuroAmount} corresponding to the value of {@link Energy} + * @return {@link EuroAmount} corresponding to the value of {@link Energy}. */ public EuroAmount toEuro(ChainParameters parameters) { BigDecimal euroPerEnergy = parameters.getEuroPerEnergy().asBigDecimal(20); @@ -48,7 +49,8 @@ public EuroAmount toEuro(ChainParameters parameters) { } /** - * Approximates the {@link CCDAmount} corresponding to the {@link Energy} using the provided {@link ChainParameters}. + * Approximates the {@link CCDAmount} amount corresponding to the {@link Energy} using the provided {@link ChainParameters}. + * Rounding may occur, so result might not be exact. * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link CCDAmount} corresponding to the value of {@link Energy}. */ diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java index 12d6150a7..88e2f2797 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java @@ -59,8 +59,8 @@ public double asDouble() { } /** - * Get the fraction as a {@link BigDecimal} value with the specified amount of digits after the decimal point. - * Last decimal is rounded using {@link RoundingMode#HALF_UP} + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Result is rounded using {@link RoundingMode#HALF_UP} * * @param precision how many decimals of precision. * @return the fraction represented as a {@link BigDecimal}. diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java index 89edd8fcd..d340d7506 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java @@ -66,6 +66,12 @@ public static CCDAmount fromBytes(ByteBuffer source) { return new CCDAmount(value); } + /** + * Approximates the {@link EuroAmount} amount corresponding to the {@link CCDAmount} using the provided {@link ChainParameters}. + * Rounding may occur, so result might not be exact. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link EuroAmount} corresponding to the value of {@link CCDAmount}. + */ public EuroAmount toEuro(ChainParameters parameters) { BigDecimal microCCDPerEuro = parameters.getMicroCCDPerEuro().asBigDecimal(20); BigDecimal ccd = new BigDecimal(this.getValue().toString()); @@ -73,6 +79,12 @@ public EuroAmount toEuro(ChainParameters parameters) { return EuroAmount.from(euros.toString()); } + /** + * Approximates the {@link Energy} amount corresponding to the {@link CCDAmount} using the provided {@link ChainParameters}. + * Rounding may occur, so result might not be exact. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link Energy} corresponding to the value of {@link CCDAmount}. + */ public Energy toEnergy(ChainParameters parameters) { return this.toEuro(parameters).toEnergy(parameters); } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java index 45cd57f31..fd66ad552 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java @@ -28,6 +28,12 @@ public static EuroAmount from(double value) { } public static EuroAmount from(String value) {return EuroAmount.from(Double.parseDouble(value));} + /** + * Approximates the {@link Energy} amount corresponding to the {@link EuroAmount} using the provided {@link ChainParameters}. + * Rounding may occur, so result might not be exact. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link Energy} corresponding to the value of {@link EuroAmount}. + */ public Energy toEnergy(ChainParameters parameters) { BigDecimal euroPerEnergy = parameters.getEuroPerEnergy().asBigDecimal(20); BigDecimal euroAmount = BigDecimal.valueOf(this.getValue()); @@ -36,6 +42,12 @@ public Energy toEnergy(ChainParameters parameters) { } + /** + * Approximates the {@link CCDAmount} amount corresponding to the {@link EuroAmount} using the provided {@link ChainParameters}. + * Rounding may occur, so result might not be exact. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link CCDAmount} corresponding to the value of {@link EuroAmount}. + */ public CCDAmount toCCD(ChainParameters parameters) { BigDecimal microCCDPerEuro = parameters.getMicroCCDPerEuro().asBigDecimal(20); BigDecimal euroAmount = BigDecimal.valueOf(this.getValue()); From 2e93d35f595539a7ba6f32d29997e7aa55a098ee Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Wed, 14 Feb 2024 13:03:47 +0100 Subject: [PATCH 04/14] Added tests and more documentation. --- .../java/com/concordium/sdk/Converter.java | 156 +++++++++++++ .../sdk/requests/smartcontracts/Energy.java | 27 --- .../concordium/sdk/responses/Fraction.java | 14 +- .../sdk/transactions/CCDAmount.java | 27 --- .../sdk/transactions/EuroAmount.java | 62 ----- .../com/concordium/sdk/types/BigFraction.java | 91 ++++++++ .../com/concordium/sdk/EnergyToCCDTest.java | 215 ++++++++++++++++++ 7 files changed, 475 insertions(+), 117 deletions(-) create mode 100644 concordium-sdk/src/main/java/com/concordium/sdk/Converter.java delete mode 100644 concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java create mode 100644 concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java create mode 100644 concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java b/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java new file mode 100644 index 000000000..df67f582a --- /dev/null +++ b/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java @@ -0,0 +1,156 @@ +package com.concordium.sdk; + +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.responses.chainparameters.ChainParameters; +import com.concordium.sdk.transactions.CCDAmount; +import com.concordium.sdk.types.BigFraction; +import com.concordium.sdk.types.UInt64; + +import java.math.BigInteger; + +/** + * Utility class for converting between {@link CCDAmount}, {@link Energy} and Euros. + * Represents converted values using {@link BigFraction} to ensure precision. + */ +public class Converter { + + /** + * Converts {@link Energy} to euro using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the euro value of {@link Energy}. + */ + public static BigFraction energyToEuro(Energy energy, ChainParameters parameters) { + BigFraction energyFraction = BigFraction.from(energy.getValue(), UInt64.from(1)); + return energyToEuro(energyFraction, parameters); + } + + /** + * Converts {@link BigFraction} representing {@link Energy} to euro using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link BigFraction} representing an amount of {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the euro value of {@link Energy}. + */ + public static BigFraction energyToEuro(BigFraction energy, ChainParameters parameters) { + BigFraction euroPerEnergy = BigFraction.from(parameters.getEuroPerEnergy()); + return mult(energy, euroPerEnergy); + } + + /** + * Converts {@link Energy} to CCD using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the CCD value of {@link Energy}. + */ + public static BigFraction energyToCCD(Energy energy, ChainParameters parameters) { + BigFraction energyFraction = BigFraction.from(energy.getValue(), UInt64.from(1)); + return energyToCCD(energyFraction, parameters); + } + + /** + * Converts {@link BigFraction} representing {@link Energy} to CCD using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link BigFraction} representing an amount of {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the CCD value of {@link Energy}. + */ + public static BigFraction energyToCCD(BigFraction energy, ChainParameters parameters) { + BigFraction euros = energyToEuro(energy, parameters); + return euroToCCD(euros, parameters); + } + + /** + * Converts {@link CCDAmount} to euros using exchange rate from the provided {@link ChainParameters}. + * + * @param ccdAmount {@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the euro value of {@link CCDAmount}. + */ + public static BigFraction ccdToEuro(CCDAmount ccdAmount, ChainParameters parameters) { + BigFraction ccd = BigFraction.from(ccdAmount.getValue(), UInt64.from(1)); + return ccdToEuro(ccd, parameters); + } + + /** + * Converts {@link BigFraction} representing {@link CCDAmount} to euros using exchange rate from the provided {@link ChainParameters}. + * + * @param ccd {@link BigFraction} representing {@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the euro value of {@link CCDAmount}. + */ + public static BigFraction ccdToEuro(BigFraction ccd, ChainParameters parameters) { + BigFraction microCCDPerEuro = BigFraction.from(parameters.getMicroCCDPerEuro()); + return div(ccd, microCCDPerEuro); + } + + /** + * Converts {@link CCDAmount} to energy using exchange rate from the provided {@link ChainParameters}. + * + * @param ccdAmount{@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the energy value of {@link CCDAmount}. + */ + public static BigFraction ccdToEnergy(CCDAmount ccdAmount, ChainParameters parameters) { + BigFraction ccd = BigFraction.from(ccdAmount.getValue(), UInt64.from(1)); + return ccdToEnergy(ccd, parameters); + } + + /** + * Converts {@link BigFraction} representing {@link CCDAmount} to energy using exchange rate from the provided {@link ChainParameters}. + * + * @param ccdAmount {@link BigFraction} representing {@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the energy value of {@link CCDAmount}. + */ + public static BigFraction ccdToEnergy(BigFraction ccdAmount, ChainParameters parameters) { + BigFraction euros = ccdToEuro(ccdAmount, parameters); + return euroToEnergy(euros, parameters); + } + + /** + * Converts {@link BigFraction} representing an amount of euros to CCD using exchange rate from the provided {@link ChainParameters}. + * + * @param euros {@link BigFraction} representing amount of euros to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the CCD value of the input. + */ + public static BigFraction euroToCCD(BigFraction euros, ChainParameters parameters) { + BigFraction microCCDPerEuro = BigFraction.from(parameters.getMicroCCDPerEuro()); + return mult(euros, microCCDPerEuro); + } + + /** + * Converts {@link BigFraction} representing an amount of euros to energy using exchange rate from the provided {@link ChainParameters}. + * + * @param euros {@link BigFraction} representing amount of euros to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link BigFraction} corresponding to the energy value of the input. + */ + public static BigFraction euroToEnergy(BigFraction euros, ChainParameters parameters) { + BigFraction euroPerEnergy = BigFraction.from(parameters.getEuroPerEnergy()); + return div(euros,euroPerEnergy); + } + + /** + * Helper function for multiplying {@link BigFraction}s used during conversions. + * Calculates a*c/b*d for input a/b, c/d. + */ + private static BigFraction mult(BigFraction a, BigFraction b) { + BigInteger numerator = a.getNumerator().multiply(b.getNumerator()); + BigInteger denominator = a.getDenominator().multiply(b.getDenominator()); + return BigFraction.from(numerator, denominator); + } + + /** + * Helper function for dividing {@link BigFraction}s used during conversions. + * Calculates a*d/b*c for input a/b, c/d. + */ + private static BigFraction div(BigFraction a, BigFraction b) { + BigInteger numerator = a.getNumerator().multiply(b.getDenominator()); + BigInteger denominator = a.getDenominator().multiply(b.getNumerator()); + return BigFraction.from(numerator, denominator); + } +} diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java index 7f98e5e48..684a6af6d 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/Energy.java @@ -1,15 +1,10 @@ package com.concordium.sdk.requests.smartcontracts; -import com.concordium.sdk.responses.chainparameters.ChainParameters; -import com.concordium.sdk.transactions.CCDAmount; -import com.concordium.sdk.transactions.EuroAmount; import com.concordium.sdk.types.UInt64; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; -import java.math.BigDecimal; - /** * Represents energy, i.e. the cost of executing transactions on the chain. */ @@ -35,26 +30,4 @@ public static Energy from(String val) { return Energy.from(UInt64.from(val)); } - /** - * Approximates the {@link EuroAmount} amount corresponding to the {@link Energy} using the provided {@link ChainParameters}. - * Rounding may occur, so result might not be exact. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link EuroAmount} corresponding to the value of {@link Energy}. - */ - public EuroAmount toEuro(ChainParameters parameters) { - BigDecimal euroPerEnergy = parameters.getEuroPerEnergy().asBigDecimal(20); - BigDecimal energy = new BigDecimal(this.getValue().toString()); - BigDecimal euros = energy.multiply(euroPerEnergy); - return EuroAmount.from(euros.toString()); - } - - /** - * Approximates the {@link CCDAmount} amount corresponding to the {@link Energy} using the provided {@link ChainParameters}. - * Rounding may occur, so result might not be exact. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link CCDAmount} corresponding to the value of {@link Energy}. - */ - public CCDAmount toCCD(ChainParameters parameters) { - return this.toEuro(parameters).toCCD(parameters); - } } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java index 88e2f2797..d859deb2f 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java @@ -66,8 +66,20 @@ public double asDouble() { * @return the fraction represented as a {@link BigDecimal}. */ public BigDecimal asBigDecimal(int precision) { + return asBigDecimal(precision, RoundingMode.HALF_UP); + } + + /** + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Result is rounded using the provided {@link RoundingMode}. + * + * @param precision how many decimals of precision. + * @param roundingMode the {@link RoundingMode} to use. + * @return the fraction represented as a {@link BigDecimal}. + */ + public BigDecimal asBigDecimal(int precision, RoundingMode roundingMode) { BigDecimal numerator = new BigDecimal(this.numerator.toString()); BigDecimal denominator = new BigDecimal(this.denominator.toString()); - return numerator.divide(denominator, precision, RoundingMode.HALF_UP); + return numerator.divide(denominator, precision, roundingMode); } } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java index d340d7506..0069a730c 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/CCDAmount.java @@ -1,16 +1,12 @@ package com.concordium.sdk.transactions; import com.concordium.grpc.v2.Amount; -import com.concordium.sdk.requests.smartcontracts.Energy; -import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.types.UInt64; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.EqualsAndHashCode; import lombok.Getter; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.nio.ByteBuffer; /** @@ -66,29 +62,6 @@ public static CCDAmount fromBytes(ByteBuffer source) { return new CCDAmount(value); } - /** - * Approximates the {@link EuroAmount} amount corresponding to the {@link CCDAmount} using the provided {@link ChainParameters}. - * Rounding may occur, so result might not be exact. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link EuroAmount} corresponding to the value of {@link CCDAmount}. - */ - public EuroAmount toEuro(ChainParameters parameters) { - BigDecimal microCCDPerEuro = parameters.getMicroCCDPerEuro().asBigDecimal(20); - BigDecimal ccd = new BigDecimal(this.getValue().toString()); - BigDecimal euros = ccd.divide(microCCDPerEuro, 20, RoundingMode.HALF_UP); - return EuroAmount.from(euros.toString()); - } - - /** - * Approximates the {@link Energy} amount corresponding to the {@link CCDAmount} using the provided {@link ChainParameters}. - * Rounding may occur, so result might not be exact. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link Energy} corresponding to the value of {@link CCDAmount}. - */ - public Energy toEnergy(ChainParameters parameters) { - return this.toEuro(parameters).toEnergy(parameters); - } - @Override public String toString() { return this.getValue().toString() + " micro CCD"; diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java b/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java deleted file mode 100644 index fd66ad552..000000000 --- a/concordium-sdk/src/main/java/com/concordium/sdk/transactions/EuroAmount.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.concordium.sdk.transactions; - - -import com.concordium.sdk.requests.smartcontracts.Energy; -import com.concordium.sdk.responses.chainparameters.ChainParameters; -import com.concordium.sdk.types.UInt64; -import lombok.EqualsAndHashCode; -import lombok.Getter; - -import java.math.BigDecimal; -import java.math.RoundingMode; - -/** - * An amount of Euros. - */ -@Getter -@EqualsAndHashCode -public class EuroAmount { - - private final double value; - - private EuroAmount(double value) { - this.value = value; - } - - public static EuroAmount from(double value) { - return new EuroAmount(value); - } - public static EuroAmount from(String value) {return EuroAmount.from(Double.parseDouble(value));} - - /** - * Approximates the {@link Energy} amount corresponding to the {@link EuroAmount} using the provided {@link ChainParameters}. - * Rounding may occur, so result might not be exact. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link Energy} corresponding to the value of {@link EuroAmount}. - */ - public Energy toEnergy(ChainParameters parameters) { - BigDecimal euroPerEnergy = parameters.getEuroPerEnergy().asBigDecimal(20); - BigDecimal euroAmount = BigDecimal.valueOf(this.getValue()); - BigDecimal energy = euroAmount.divide(euroPerEnergy, 20, RoundingMode.HALF_UP); - return Energy.from(UInt64.from(energy.longValue())); - - } - - /** - * Approximates the {@link CCDAmount} amount corresponding to the {@link EuroAmount} using the provided {@link ChainParameters}. - * Rounding may occur, so result might not be exact. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link CCDAmount} corresponding to the value of {@link EuroAmount}. - */ - public CCDAmount toCCD(ChainParameters parameters) { - BigDecimal microCCDPerEuro = parameters.getMicroCCDPerEuro().asBigDecimal(20); - BigDecimal euroAmount = BigDecimal.valueOf(this.getValue()); - BigDecimal ccd = euroAmount.multiply(microCCDPerEuro); - return CCDAmount.fromMicro(ccd.longValue()); - } - - @Override - public String toString() { - return this.getValue() + " Euros"; - } -} diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java b/concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java new file mode 100644 index 000000000..a3b3fbdad --- /dev/null +++ b/concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java @@ -0,0 +1,91 @@ +package com.concordium.sdk.types; + +import com.concordium.sdk.Converter; +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.responses.Fraction; +import com.concordium.sdk.transactions.CCDAmount; +import lombok.Builder; +import lombok.Getter; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; + +/** + * For representing fractions with large numerators or denominators. Used in {@link Converter} to convert to/from {@link CCDAmount} and {@link Energy}. + * Use {@link BigFraction#asBigDecimal(int)} to get numeric value of the fraction. + */ +@Getter +@Builder +public class BigFraction { + + /** + * Numerator of the fraction. + */ + private BigInteger numerator; + /** + * Denominator of the fraction. + */ + private BigInteger denominator; + + public static BigFraction from(BigInteger numerator, BigInteger denominator) { + return new BigFraction(numerator, denominator); + } + + public static BigFraction from(UInt64 numerator, UInt64 denominator) { + return new BigFraction(new BigInteger(numerator.toString()), new BigInteger(denominator.toString())); + } + + public static BigFraction from(Fraction fraction) { + return from(fraction.getNumerator(),fraction.getDenominator()); + } + @Override + public String toString() { + return this.numerator + "/" + this.denominator; + } + + /** + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Result is rounded using {@link RoundingMode#HALF_UP} + * + * @param precision how many decimals of precision. + * @return the fraction represented as a {@link BigDecimal}. + */ + public BigDecimal asBigDecimal(int precision) { + return asBigDecimal(precision, RoundingMode.HALF_UP); + } + + /** + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Result is rounded using the provided {@link RoundingMode}. + * + * @param precision how many decimals of precision. + * @param roundingMode the {@link RoundingMode} to use. + * @return the fraction represented as a {@link BigDecimal}. + */ + public BigDecimal asBigDecimal(int precision, RoundingMode roundingMode) { + BigDecimal numerator = new BigDecimal(this.getNumerator()); + BigDecimal denominator = new BigDecimal(this.getDenominator()); + return numerator.divide(denominator, precision, roundingMode); + } + + @Override + public boolean equals(Object o) { + + if (o == this) { + return true; + } + + if (!(o instanceof BigFraction)) { + return false; + } + + BigFraction otherFraction = (BigFraction) o; + + // Comparison done using cross multiplication. a * d = b * c => a/b = c/d + BigInteger ad = this.numerator.multiply(otherFraction.denominator); + BigInteger bc = this.denominator.multiply(otherFraction.numerator); + return ad.equals(bc); + } + +} diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java new file mode 100644 index 000000000..29c85293d --- /dev/null +++ b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java @@ -0,0 +1,215 @@ +package com.concordium.sdk; + +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.responses.Fraction; +import com.concordium.sdk.responses.chainparameters.ChainParameters; +import com.concordium.sdk.transactions.CCDAmount; +import com.concordium.sdk.types.BigFraction; +import com.concordium.sdk.types.UInt64; +import lombok.SneakyThrows; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests the different conversions between {@link Energy} and {@link CCDAmount}. + */ +public class EnergyToCCDTest { + + private static final long CCD_LONG = 1000000; + private static final long ENERGY_LONG = 10000; + + private static final CCDAmount CCD_AMOUNT = CCDAmount.fromMicro(CCD_LONG); + private static final Energy ENERGY = Energy.from(UInt64.from(ENERGY_LONG)); + + private static final BigFraction CCD_FRACTION = BigFraction.from(CCD_AMOUNT.getValue(), UInt64.from(1)); + private static final BigFraction ENERGY_FRACTION = BigFraction.from(ENERGY.getValue(), UInt64.from(1)); + private static final BigFraction EURO_FRACTION = BigFraction.from(UInt64.from(10), UInt64.from(1)); + + // Euro per energy doesn't change value and isn't nearly as big so can use same value for tests. + private static final Fraction EURO_PER_ENERGY = new Fraction(UInt64.from("1"), UInt64.from("1100000")); + + // 16626124143116419072/78228883861 + private static final Fraction MICRO_CCD_PER_EURO_1 = new Fraction(UInt64.from("16626124143116419072"), UInt64.from("78228883861")); + + // 13578063771458994176/62220885881 + private static final Fraction MICRO_CCD_PER_EURO_2 = new Fraction(UInt64.from("13578063771458994176"), UInt64.from("62220885881")); + + // 3465558596452424320/16276715619 + private static final Fraction MICRO_CCD_PER_EURO_3 = new Fraction(UInt64.from("3465558596452424320"), UInt64.from("16276715619")); + + // 5414544070782746624/24832708375 + private static final Fraction MICRO_CCD_PER_EURO_4 = new Fraction(UInt64.from("5414544070782746624"), UInt64.from("24832708375")); + private static final ChainParameters PARAM_1 = mock(ChainParameters.class); + private static final ChainParameters PARAM_2 = mock(ChainParameters.class); + private static final ChainParameters PARAM_3 = mock(ChainParameters.class); + private static final ChainParameters PARAM_4 = mock(ChainParameters.class); + + private static final List PARAMETERS_LIST = new ArrayList<>(); + + // Setup mock parameters with different ccd/euro ratios. + static { + when(PARAM_1.getMicroCCDPerEuro()).thenReturn(MICRO_CCD_PER_EURO_1); + when(PARAM_2.getMicroCCDPerEuro()).thenReturn(MICRO_CCD_PER_EURO_2); + when(PARAM_3.getMicroCCDPerEuro()).thenReturn(MICRO_CCD_PER_EURO_3); + when(PARAM_4.getMicroCCDPerEuro()).thenReturn(MICRO_CCD_PER_EURO_4); + + when(PARAM_1.getEuroPerEnergy()).thenReturn(EURO_PER_ENERGY); + when(PARAM_2.getEuroPerEnergy()).thenReturn(EURO_PER_ENERGY); + when(PARAM_3.getEuroPerEnergy()).thenReturn(EURO_PER_ENERGY); + when(PARAM_4.getEuroPerEnergy()).thenReturn(EURO_PER_ENERGY); + + PARAMETERS_LIST.add(PARAM_1); + PARAMETERS_LIST.add(PARAM_2); + PARAMETERS_LIST.add(PARAM_3); + PARAMETERS_LIST.add(PARAM_4); + } + + + @SneakyThrows + @Test + public void testShouldBePrecise() { + for (ChainParameters parameters : PARAMETERS_LIST) { + // Converting Energy + energyToCCD(parameters); + energyToEuro(parameters); + // Converting CCD + ccdToEnergy(parameters); + ccdToEuro(parameters); + // Converting Euro + euroToEnergy(parameters); + euroToCCD(parameters); + } + } + + private void energyToCCD(ChainParameters parameters) { + BigFraction ccdFromEnergy = Converter.energyToCCD(ENERGY, parameters); + BigFraction ccdFromEnergyFraction = Converter.energyToCCD(ENERGY_FRACTION, parameters); + // Both conversions receive same result + assertEquals(ccdFromEnergy, ccdFromEnergyFraction); + + BigFraction energyFromCCD = Converter.ccdToEnergy(ccdFromEnergy, parameters); + BigFraction energyFromCCDFraction = Converter.ccdToEnergy(ccdFromEnergyFraction, parameters); + + // Converting back receives same result + assertEquals(energyFromCCD, energyFromCCDFraction); + + // Converting back is precise + assertEquals(energyFromCCD, ENERGY_FRACTION); + } + + private void energyToEuro(ChainParameters parameters) { + BigFraction euroFromEnergy = Converter.energyToEuro(ENERGY, parameters); + BigFraction euroFromEnergyFraction = Converter.energyToEuro(ENERGY_FRACTION, parameters); + // Both conversions receive same result + assertEquals(euroFromEnergy, euroFromEnergyFraction); + + BigFraction energyFromEuro = Converter.euroToEnergy(euroFromEnergy, parameters); + BigFraction energyFromEuroFraction = Converter.euroToEnergy(euroFromEnergyFraction, parameters); + + // Converting back receives same result + assertEquals(energyFromEuro, energyFromEuroFraction); + + // Converting back is precise + assertEquals(energyFromEuro, ENERGY_FRACTION); + } + private void ccdToEnergy(ChainParameters parameters) { + BigFraction energyFromCCD = Converter.ccdToEnergy(CCD_AMOUNT, parameters); + BigFraction energyFromCCDFraction = Converter.ccdToEnergy(CCD_FRACTION, parameters); + + // Both conversions receive same result + assertEquals(energyFromCCD, energyFromCCDFraction); + + BigFraction ccdFromEnergy = Converter.energyToCCD(energyFromCCD, parameters); + BigFraction ccdFromEnergyFraction = Converter.energyToCCD(energyFromCCDFraction, parameters); + + // Converting back receives same result + assertEquals(ccdFromEnergy, ccdFromEnergyFraction); + + // Converting back is precise + assertEquals(ccdFromEnergy, CCD_FRACTION); + } + private void ccdToEuro(ChainParameters parameters) { + BigFraction euroFromCCD = Converter.ccdToEuro(CCD_AMOUNT, parameters); + BigFraction euroFromCCDFraction = Converter.ccdToEuro(CCD_FRACTION, parameters); + // Both conversions receive same result + assertEquals(euroFromCCD,euroFromCCDFraction); + + BigFraction ccdFromEuro = Converter.euroToCCD(euroFromCCD, parameters); + BigFraction ccdFromEuroFraction = Converter.euroToCCD(euroFromCCDFraction, parameters); + + // Converting back receives same result + assertEquals(ccdFromEuro, ccdFromEuroFraction); + + // Converting back is precise + assertEquals(ccdFromEuro, CCD_FRACTION); + } + private void euroToEnergy(ChainParameters parameters) { + BigFraction energyFromEuro = Converter.euroToEnergy(EURO_FRACTION, parameters); + BigFraction euroFromEnergy = Converter.energyToEuro(energyFromEuro, parameters); + + // Conversions are precise + assertEquals(euroFromEnergy, EURO_FRACTION); + } + private void euroToCCD(ChainParameters parameters) { + BigFraction ccdFromEuro = Converter.euroToCCD(EURO_FRACTION, parameters); + BigFraction euroFromCCD = Converter.ccdToEuro(ccdFromEuro, parameters); + + // Conversions are precise + assertEquals(euroFromCCD, EURO_FRACTION); + } + + /** + * Asserts that the calculations performed when using PARAM_1 gives the correct result. + */ + @Test + public void testActualValues() { + // EURO_PER_ENERGY * ENERGY = 1/1100000×10000 = 1/110 + BigFraction expectedEuroFromEnergy = frac("1", "110"); + BigFraction euroFromEnergy = Converter.energyToEuro(ENERGY, PARAM_1); + assertEquals(expectedEuroFromEnergy, euroFromEnergy); + + // MICRO_CCD_PER_EURO_1 * EURO = 16626124143116419072/78228883861 * 10 = 166261241431164190720/78228883861 + BigFraction expectedCCDFromEuro = frac("166261241431164190720","78228883861"); + BigFraction ccdFromEuro = Converter.euroToCCD(EURO_FRACTION, PARAM_1); + assertEquals(expectedCCDFromEuro, ccdFromEuro); + + // EURO_PER_ENERGY * ENERGY * MICRO_CCD_PER_EURO_1 = 1/110 * 16626124143116419072/78228883861 = 8313062071558209536/4302588612355 + BigFraction expectedCCDFromEnergy = frac("8313062071558209536", "4302588612355"); + BigFraction ccdFromEnergy = Converter.energyToCCD(ENERGY, PARAM_1); + assertEquals(expectedCCDFromEnergy, ccdFromEnergy); + + // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 = 1000000 / (16626124143116419072/78228883861) = 1222326310328125/259783189736194048 + BigFraction expectedEuroFromCCD = frac("1222326310328125", "259783189736194048"); + BigFraction euroFromCCD = Converter.ccdToEuro(CCD_AMOUNT, PARAM_1); + assertEquals(expectedEuroFromCCD, euroFromCCD); + + // EUROS / EURO_PER_ENERGY = 10 / (1/1100000) = 11000000 + BigFraction expectedEnergyFromEuro = frac("11000000", "1"); + BigFraction energyFromEuro = Converter.euroToEnergy(EURO_FRACTION, PARAM_1); + assertEquals(expectedEnergyFromEuro, energyFromEuro); + + // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 / EUROS_PER_ENERGY = + // (1000000 / (16626124143116419072/78228883861)) / (1/1100000) = + // 42017466917529296875/8118224679256064 + BigFraction expectedEnergyFromCCD = frac("42017466917529296875", "8118224679256064"); + BigFraction energyFromCCD = Converter.ccdToEnergy(CCD_AMOUNT, PARAM_1); + assertEquals(expectedEnergyFromCCD, energyFromCCD); + } + + private BigFraction frac(String a, String b) { + return BigFraction.from(new BigInteger(a),new BigInteger(b)); + } + + + + + + +} From 878b4ec5e33459a9566901cb85f28bfd2adff109 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Wed, 14 Feb 2024 13:07:08 +0100 Subject: [PATCH 05/14] Updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06e12da95..c5310983f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased changes +- Added utility functions for converting between `CCDAmount` and `Energy`. Present in utility class `Converter`. - Make the `energy` parameter for invoking an instance `Optional`. - Parse the underlying reject reasons into `AccountTransactionDetails`. - Introduced Cis2Client for interfacing with CIS2 compliant smart contracts. From 2c7a15536fbb1f7ddba837dc5ccad5512136a6f4 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Wed, 14 Feb 2024 14:43:43 +0100 Subject: [PATCH 06/14] Removed unnecessary `amount` parameter from InvokeInstanceRequest --- CHANGELOG.md | 1 + .../main/java/com/concordium/sdk/ClientV2.java | 2 +- .../com/concordium/sdk/cis2/Cis2Client.java | 16 +++------------- .../smartcontracts/InvokeInstanceRequest.java | 18 ++---------------- 4 files changed, 7 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5310983f..f13c7cd84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased changes +- Removed unnecessary `amount` parameter from `InvokeInstanceRequest`. - Added utility functions for converting between `CCDAmount` and `Energy`. Present in utility class `Converter`. - Make the `energy` parameter for invoking an instance `Optional`. - Parse the underlying reject reasons into `AccountTransactionDetails`. diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/ClientV2.java b/concordium-sdk/src/main/java/com/concordium/sdk/ClientV2.java index e149a4682..cdbab1179 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/ClientV2.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/ClientV2.java @@ -791,7 +791,7 @@ public InvokeInstanceResult invokeInstance(InvokeInstanceRequest request) { grpcRequest.setInvoker(to(request.getInvoker())); } grpcRequest.setInstance(to(request.getInstance())) - .setAmount(to(request.getAmount())) + .setAmount(to(CCDAmount.from(0))) .setEntrypoint(to(request.getEntrypoint())) .setParameter(to(request.getParameter())); if (request.getEnergy().isPresent()) { diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/cis2/Cis2Client.java b/concordium-sdk/src/main/java/com/concordium/sdk/cis2/Cis2Client.java index 32c1889ab..bb70875b2 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/cis2/Cis2Client.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/cis2/Cis2Client.java @@ -1,30 +1,20 @@ package com.concordium.sdk.cis2; import com.concordium.sdk.ClientV2; -import com.concordium.sdk.cis2.events.Cis2Event; import com.concordium.sdk.cis2.events.Cis2EventWithMetadata; import com.concordium.sdk.requests.AccountQuery; import com.concordium.sdk.requests.BlockQuery; import com.concordium.sdk.requests.smartcontracts.Energy; import com.concordium.sdk.requests.smartcontracts.InvokeInstanceRequest; -import com.concordium.sdk.responses.blockitemstatus.FinalizedBlockItem; -import com.concordium.sdk.responses.blockitemsummary.Summary; -import com.concordium.sdk.responses.blockitemsummary.Type; import com.concordium.sdk.responses.blocksatheight.BlocksAtHeightRequest; -import com.concordium.sdk.responses.smartcontracts.ContractTraceElement; -import com.concordium.sdk.responses.smartcontracts.ContractTraceElementType; -import com.concordium.sdk.responses.transactionstatus.ContractUpdated; import com.concordium.sdk.responses.transactionstatus.Outcome; -import com.concordium.sdk.responses.transactionstatus.TransactionResultEventType; import com.concordium.sdk.transactions.*; import com.concordium.sdk.types.*; import com.google.common.collect.Lists; import lombok.Getter; import lombok.val; -import lombok.var; import java.util.*; -import java.util.stream.Collectors; /** * A client dedicated to the CIS2 specification. @@ -112,7 +102,7 @@ public Map balanceOf(BalanceQuery... queries) { val listOfQueries = Arrays.asList(queries); val parameter = SerializationUtils.serializeBalanceOfParameter(listOfQueries); val endpoint = ReceiveName.from(contractName, "balanceOf"); - val result = this.client.invokeInstance(InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, this.contractAddress, CCDAmount.from(0), endpoint, parameter, Optional.empty())); + val result = this.client.invokeInstance(InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, this.contractAddress, endpoint, parameter, Optional.empty())); if (result.getOutcome() == Outcome.REJECT) { throw new RuntimeException("balanceOf failed: " + result.getRejectReason().toString()); } @@ -134,7 +124,7 @@ public Map operatorOf(OperatorQuery... queries) { val listOfQueries = Arrays.asList(queries); val parameter = SerializationUtils.serializeOperatorOfParameter(listOfQueries); val endpoint = ReceiveName.from(contractName, "operatorOf"); - val result = this.client.invokeInstance(InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, this.contractAddress, CCDAmount.from(0), endpoint, parameter, Optional.empty())); + val result = this.client.invokeInstance(InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, this.contractAddress, endpoint, parameter, Optional.empty())); if (result.getOutcome() == Outcome.REJECT) { throw new RuntimeException("operatorOf failed: " + result.getRejectReason().toString()); } @@ -156,7 +146,7 @@ public Map tokenMetadata(TokenId... tokenIds) { val listOfQueries = Arrays.asList(tokenIds); val parameter = SerializationUtils.serializeTokenIds(listOfQueries); val endpoint = ReceiveName.from(contractName, "tokenMetadata"); - val result = this.client.invokeInstance(InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, this.contractAddress, CCDAmount.from(0), endpoint, parameter, Optional.empty())); + val result = this.client.invokeInstance(InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, this.contractAddress, endpoint, parameter, Optional.empty())); if (result.getOutcome() == Outcome.REJECT) { throw new RuntimeException("tokenMetadata failed: " + result.getRejectReason().toString()); } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/InvokeInstanceRequest.java b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/InvokeInstanceRequest.java index e42e36cb0..73e77f9a1 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/InvokeInstanceRequest.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/requests/smartcontracts/InvokeInstanceRequest.java @@ -38,10 +38,6 @@ public class InvokeInstanceRequest { */ private ContractAddress instance; - /** - * Amount to invoke the smart contract instance with. - */ - private CCDAmount amount; /** * The entrypoint of the smart contract instance to invoke. @@ -70,7 +66,6 @@ public class InvokeInstanceRequest { * If this is not supplied then the contract will be invoked by an account with address 0, * no credentials and sufficient amount of CCD to cover the transfer amount. * @param instance Address of the contract instance to invoke. - * @param amount Amount to invoke the smart contract instance with. * @param entrypoint The {@link ReceiveName} of the smart contract instance to invoke. * @param parameter The parameter bytes to include in the invocation of the entrypoint. * @param energy The amount of energy to allow for execution. If this is not set, then the node @@ -79,7 +74,6 @@ public class InvokeInstanceRequest { public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, @NonNull AbstractAddress invoker, @NonNull ContractAddress instance, - @NonNull CCDAmount amount, @NonNull ReceiveName entrypoint, @NonNull Parameter parameter, @NonNull Optional energy) { @@ -87,7 +81,6 @@ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, .blockHash(blockHash) .invoker(invoker) .instance(instance) - .amount(amount) .entrypoint(entrypoint) .parameter(parameter) .energy(energy).build(); @@ -99,7 +92,6 @@ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, * * @param blockHash Block to invoke the contract. The invocation will be at the end of the given block. * @param instance Address of the contract instance to invoke. - * @param amount Amount to invoke the smart contract instance with. * @param entrypoint The {@link ReceiveName} of the smart contract instance to invoke. * @param parameter The parameter bytes to include in the invocation of the entrypoint. * @param energy The amount of energy to allow for execution. If this is not set, then the node @@ -107,14 +99,12 @@ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, */ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, @NonNull ContractAddress instance, - @NonNull CCDAmount amount, @NonNull ReceiveName entrypoint, @NonNull Parameter parameter, @NonNull Optional energy) { return InvokeInstanceRequest.builder() .blockHash(blockHash) .instance(instance) - .amount(amount) .entrypoint(entrypoint) .parameter(parameter) .energy(energy).build(); @@ -128,7 +118,6 @@ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, * If this is not supplied then the contract will be invoked by an account with address 0, * no credentials and sufficient amount of CCD to cover the transfer amount. * @param instance Address of the contract instance to invoke. - * @param amount Amount to invoke the smart contract instance with. * @param schemaParameter {@link SchemaParameter} message to invoke the contract with. Must be initialized with {@link SchemaParameter#initialize()} beforehand. * @param energy The amount of energy to allow for execution. If this is not set, then the node * will decide a sufficient amount of energy allowed for transaction execution. @@ -136,13 +125,12 @@ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, @NonNull AbstractAddress invoker, @NonNull ContractAddress instance, - @NonNull CCDAmount amount, @NonNull SchemaParameter schemaParameter, @NonNull Optional energy) { if (!(schemaParameter.getType() == ParameterType.RECEIVE)) { throw new IllegalArgumentException("Cannot initialize smart contract with InvokeInstance. SchemaParameter for InvokeInstanceRequest must be initialized with a ReceiveName"); } - return from(blockHash, invoker, instance, amount, schemaParameter.getReceiveName(), Parameter.from(schemaParameter), energy); + return from(blockHash, invoker, instance, schemaParameter.getReceiveName(), Parameter.from(schemaParameter), energy); } /** @@ -151,20 +139,18 @@ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, * * @param blockHash Block to invoke the contract. The invocation will be at the end of the given block. * @param instance Address of the contract instance to invoke. - * @param amount Amount to invoke the smart contract instance with. * @param schemaParameter {@link SchemaParameter} message to invoke the contract with. Must be initialized with {@link SchemaParameter#initialize()} beforehand. * @param energy The amount of energy to allow for execution. If this is not set, then the node * will decide a sufficient amount of energy allowed for transaction execution. */ public static InvokeInstanceRequest from(@NonNull BlockQuery blockHash, @NonNull ContractAddress instance, - @NonNull CCDAmount amount, @NonNull SchemaParameter schemaParameter, @NonNull Optional energy) { if (!(schemaParameter.getType() == ParameterType.RECEIVE)) { throw new IllegalArgumentException("Cannot initialize smart contract with InvokeInstance. SchemaParameter for InvokeInstanceRequest must be initialized with a ReceiveName"); } - return from(blockHash, instance, amount, schemaParameter.getReceiveName(), Parameter.from(schemaParameter), energy); + return from(blockHash, instance, schemaParameter.getReceiveName(), Parameter.from(schemaParameter), energy); } public boolean hasInvoker() { From 9b867c0a72ebffdf899e94ae660bd52045e63822 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Wed, 14 Feb 2024 14:48:48 +0100 Subject: [PATCH 07/14] Clearer naming --- .../java/com/concordium/sdk/Converter.java | 30 +++++++++---------- .../com/concordium/sdk/EnergyToCCDTest.java | 26 ++++++++-------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java b/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java index df67f582a..3444842a4 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java @@ -39,27 +39,27 @@ public static BigFraction energyToEuro(BigFraction energy, ChainParameters param } /** - * Converts {@link Energy} to CCD using exchange rate from the provided {@link ChainParameters}. + * Converts {@link Energy} to micro CCD using exchange rate from the provided {@link ChainParameters}. * * @param energy {@link Energy} to convert. * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the CCD value of {@link Energy}. + * @return {@link BigFraction} corresponding to the micro CCD value of {@link Energy}. */ - public static BigFraction energyToCCD(Energy energy, ChainParameters parameters) { + public static BigFraction energyToMicroCCD(Energy energy, ChainParameters parameters) { BigFraction energyFraction = BigFraction.from(energy.getValue(), UInt64.from(1)); - return energyToCCD(energyFraction, parameters); + return energyToMicroCCD(energyFraction, parameters); } /** - * Converts {@link BigFraction} representing {@link Energy} to CCD using exchange rate from the provided {@link ChainParameters}. + * Converts {@link BigFraction} representing {@link Energy} to micro CCD using exchange rate from the provided {@link ChainParameters}. * * @param energy {@link BigFraction} representing an amount of {@link Energy} to convert. * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the CCD value of {@link Energy}. + * @return {@link BigFraction} corresponding to the micro CCD value of {@link Energy}. */ - public static BigFraction energyToCCD(BigFraction energy, ChainParameters parameters) { + public static BigFraction energyToMicroCCD(BigFraction energy, ChainParameters parameters) { BigFraction euros = energyToEuro(energy, parameters); - return euroToCCD(euros, parameters); + return euroToMicroCCD(euros, parameters); } /** @@ -69,9 +69,9 @@ public static BigFraction energyToCCD(BigFraction energy, ChainParameters parame * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link BigFraction} corresponding to the euro value of {@link CCDAmount}. */ - public static BigFraction ccdToEuro(CCDAmount ccdAmount, ChainParameters parameters) { + public static BigFraction microCCDToEuro(CCDAmount ccdAmount, ChainParameters parameters) { BigFraction ccd = BigFraction.from(ccdAmount.getValue(), UInt64.from(1)); - return ccdToEuro(ccd, parameters); + return microCCDToEuro(ccd, parameters); } /** @@ -81,7 +81,7 @@ public static BigFraction ccdToEuro(CCDAmount ccdAmount, ChainParameters paramet * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link BigFraction} corresponding to the euro value of {@link CCDAmount}. */ - public static BigFraction ccdToEuro(BigFraction ccd, ChainParameters parameters) { + public static BigFraction microCCDToEuro(BigFraction ccd, ChainParameters parameters) { BigFraction microCCDPerEuro = BigFraction.from(parameters.getMicroCCDPerEuro()); return div(ccd, microCCDPerEuro); } @@ -106,18 +106,18 @@ public static BigFraction ccdToEnergy(CCDAmount ccdAmount, ChainParameters param * @return {@link BigFraction} corresponding to the energy value of {@link CCDAmount}. */ public static BigFraction ccdToEnergy(BigFraction ccdAmount, ChainParameters parameters) { - BigFraction euros = ccdToEuro(ccdAmount, parameters); + BigFraction euros = microCCDToEuro(ccdAmount, parameters); return euroToEnergy(euros, parameters); } /** - * Converts {@link BigFraction} representing an amount of euros to CCD using exchange rate from the provided {@link ChainParameters}. + * Converts {@link BigFraction} representing an amount of euros to micro CCD using exchange rate from the provided {@link ChainParameters}. * * @param euros {@link BigFraction} representing amount of euros to convert. * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the CCD value of the input. + * @return {@link BigFraction} corresponding to the micro CCD value of the input. */ - public static BigFraction euroToCCD(BigFraction euros, ChainParameters parameters) { + public static BigFraction euroToMicroCCD(BigFraction euros, ChainParameters parameters) { BigFraction microCCDPerEuro = BigFraction.from(parameters.getMicroCCDPerEuro()); return mult(euros, microCCDPerEuro); } diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java index 29c85293d..bb6db87dd 100644 --- a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java +++ b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java @@ -89,8 +89,8 @@ public void testShouldBePrecise() { } private void energyToCCD(ChainParameters parameters) { - BigFraction ccdFromEnergy = Converter.energyToCCD(ENERGY, parameters); - BigFraction ccdFromEnergyFraction = Converter.energyToCCD(ENERGY_FRACTION, parameters); + BigFraction ccdFromEnergy = Converter.energyToMicroCCD(ENERGY, parameters); + BigFraction ccdFromEnergyFraction = Converter.energyToMicroCCD(ENERGY_FRACTION, parameters); // Both conversions receive same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); @@ -126,8 +126,8 @@ private void ccdToEnergy(ChainParameters parameters) { // Both conversions receive same result assertEquals(energyFromCCD, energyFromCCDFraction); - BigFraction ccdFromEnergy = Converter.energyToCCD(energyFromCCD, parameters); - BigFraction ccdFromEnergyFraction = Converter.energyToCCD(energyFromCCDFraction, parameters); + BigFraction ccdFromEnergy = Converter.energyToMicroCCD(energyFromCCD, parameters); + BigFraction ccdFromEnergyFraction = Converter.energyToMicroCCD(energyFromCCDFraction, parameters); // Converting back receives same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); @@ -136,13 +136,13 @@ private void ccdToEnergy(ChainParameters parameters) { assertEquals(ccdFromEnergy, CCD_FRACTION); } private void ccdToEuro(ChainParameters parameters) { - BigFraction euroFromCCD = Converter.ccdToEuro(CCD_AMOUNT, parameters); - BigFraction euroFromCCDFraction = Converter.ccdToEuro(CCD_FRACTION, parameters); + BigFraction euroFromCCD = Converter.microCCDToEuro(CCD_AMOUNT, parameters); + BigFraction euroFromCCDFraction = Converter.microCCDToEuro(CCD_FRACTION, parameters); // Both conversions receive same result assertEquals(euroFromCCD,euroFromCCDFraction); - BigFraction ccdFromEuro = Converter.euroToCCD(euroFromCCD, parameters); - BigFraction ccdFromEuroFraction = Converter.euroToCCD(euroFromCCDFraction, parameters); + BigFraction ccdFromEuro = Converter.euroToMicroCCD(euroFromCCD, parameters); + BigFraction ccdFromEuroFraction = Converter.euroToMicroCCD(euroFromCCDFraction, parameters); // Converting back receives same result assertEquals(ccdFromEuro, ccdFromEuroFraction); @@ -158,8 +158,8 @@ private void euroToEnergy(ChainParameters parameters) { assertEquals(euroFromEnergy, EURO_FRACTION); } private void euroToCCD(ChainParameters parameters) { - BigFraction ccdFromEuro = Converter.euroToCCD(EURO_FRACTION, parameters); - BigFraction euroFromCCD = Converter.ccdToEuro(ccdFromEuro, parameters); + BigFraction ccdFromEuro = Converter.euroToMicroCCD(EURO_FRACTION, parameters); + BigFraction euroFromCCD = Converter.microCCDToEuro(ccdFromEuro, parameters); // Conversions are precise assertEquals(euroFromCCD, EURO_FRACTION); @@ -177,17 +177,17 @@ public void testActualValues() { // MICRO_CCD_PER_EURO_1 * EURO = 16626124143116419072/78228883861 * 10 = 166261241431164190720/78228883861 BigFraction expectedCCDFromEuro = frac("166261241431164190720","78228883861"); - BigFraction ccdFromEuro = Converter.euroToCCD(EURO_FRACTION, PARAM_1); + BigFraction ccdFromEuro = Converter.euroToMicroCCD(EURO_FRACTION, PARAM_1); assertEquals(expectedCCDFromEuro, ccdFromEuro); // EURO_PER_ENERGY * ENERGY * MICRO_CCD_PER_EURO_1 = 1/110 * 16626124143116419072/78228883861 = 8313062071558209536/4302588612355 BigFraction expectedCCDFromEnergy = frac("8313062071558209536", "4302588612355"); - BigFraction ccdFromEnergy = Converter.energyToCCD(ENERGY, PARAM_1); + BigFraction ccdFromEnergy = Converter.energyToMicroCCD(ENERGY, PARAM_1); assertEquals(expectedCCDFromEnergy, ccdFromEnergy); // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 = 1000000 / (16626124143116419072/78228883861) = 1222326310328125/259783189736194048 BigFraction expectedEuroFromCCD = frac("1222326310328125", "259783189736194048"); - BigFraction euroFromCCD = Converter.ccdToEuro(CCD_AMOUNT, PARAM_1); + BigFraction euroFromCCD = Converter.microCCDToEuro(CCD_AMOUNT, PARAM_1); assertEquals(expectedEuroFromCCD, euroFromCCD); // EUROS / EURO_PER_ENERGY = 10 / (1/1100000) = 11000000 From d49895370167ad006db1dd52f8f27c56a6dfbb62 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Wed, 14 Feb 2024 14:52:06 +0100 Subject: [PATCH 08/14] Calculates cost of transactions in Cis2Nft and Cis2WCCD using new utility functions in Converter --- .../contractexample/cis2nft/Cis2Nft.java | 25 ++++++++++++++++--- .../contractexample/wccd/Cis2WCCD.java | 19 ++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java index 53b62de24..a92187cfb 100644 --- a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java +++ b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java @@ -2,22 +2,25 @@ import com.concordium.sdk.ClientV2; import com.concordium.sdk.Connection; +import com.concordium.sdk.Converter; import com.concordium.sdk.crypto.ed25519.ED25519SecretKey; import com.concordium.sdk.exceptions.ClientInitializationException; import com.concordium.sdk.requests.AccountQuery; import com.concordium.sdk.requests.BlockQuery; +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.requests.smartcontracts.InvokeInstanceRequest; import com.concordium.sdk.responses.blockitemstatus.FinalizedBlockItem; +import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.responses.modulelist.ModuleRef; +import com.concordium.sdk.responses.smartcontracts.InvokeInstanceResult; import com.concordium.sdk.transactions.*; import com.concordium.sdk.transactions.smartcontracts.SchemaParameter; -import com.concordium.sdk.types.AccountAddress; -import com.concordium.sdk.types.ContractAddress; -import com.concordium.sdk.types.Nonce; -import com.concordium.sdk.types.UInt64; +import com.concordium.sdk.types.*; import lombok.var; import picocli.CommandLine; import java.io.IOException; +import java.math.BigDecimal; import java.net.URL; import java.util.Optional; import java.util.concurrent.Callable; @@ -130,6 +133,20 @@ private void handleInit(ClientV2 client, Nonce nonce) { } private void handleMethod(ClientV2 client, Nonce nonce, SchemaParameter parameter) { + + // Estimate energy used by transaction. + InvokeInstanceRequest invokeInstanceRequest = InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, + CONTRACT_ADDRESS, + parameter, + Optional.empty()); + InvokeInstanceResult invokeInstanceResult = client.invokeInstance(invokeInstanceRequest); + Energy usedEnergy = invokeInstanceResult.getUsedEnergy(); + ChainParameters parameters = client.getChainParameters(BlockQuery.LAST_FINAL); + // Convert to Euro and CCD using ChainParameters from the best block and utility methods in the Converter class. + BigDecimal euros = Converter.energyToEuro(usedEnergy, parameters).asBigDecimal(6); + BigDecimal ccd = Converter.energyToMicroCCD(usedEnergy, parameters).asBigDecimal(6); + System.out.println("Price of transaction is: " + usedEnergy + " = " + euros + " euros = " + ccd + " micro CCD"); + UpdateContract payload = UpdateContract.from(CONTRACT_ADDRESS, parameter); UpdateContractTransaction transaction = TransactionFactory.newUpdateContract() .sender(AccountAddress.from(SENDER_ADDRESS)) diff --git a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java index ca39a76cf..4e1c7f62b 100644 --- a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java +++ b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java @@ -2,11 +2,16 @@ import com.concordium.sdk.ClientV2; import com.concordium.sdk.Connection; +import com.concordium.sdk.Converter; import com.concordium.sdk.crypto.ed25519.ED25519SecretKey; import com.concordium.sdk.requests.AccountQuery; import com.concordium.sdk.requests.BlockQuery; +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.requests.smartcontracts.InvokeInstanceRequest; import com.concordium.sdk.responses.blockitemstatus.FinalizedBlockItem; +import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.responses.modulelist.ModuleRef; +import com.concordium.sdk.responses.smartcontracts.InvokeInstanceResult; import com.concordium.sdk.transactions.*; import com.concordium.sdk.transactions.smartcontracts.SchemaParameter; import com.concordium.sdk.types.AccountAddress; @@ -16,6 +21,7 @@ import lombok.var; import picocli.CommandLine; +import java.math.BigDecimal; import java.net.URL; import java.util.Optional; import java.util.concurrent.Callable; @@ -147,6 +153,19 @@ private void handleInit(ClientV2 client, Nonce nonce) { } private void handleMethod(ClientV2 client, Nonce nonce, SchemaParameter parameter) { + // Estimate energy used by transaction. + InvokeInstanceRequest invokeInstanceRequest = InvokeInstanceRequest.from(BlockQuery.LAST_FINAL, + CONTRACT_ADDRESS, + parameter, + Optional.empty()); + InvokeInstanceResult invokeInstanceResult = client.invokeInstance(invokeInstanceRequest); + Energy usedEnergy = invokeInstanceResult.getUsedEnergy(); + ChainParameters parameters = client.getChainParameters(BlockQuery.LAST_FINAL); + // Convert to Euro and CCD using ChainParameters from the best block and utility methods in the Converter class. + BigDecimal euros = Converter.energyToEuro(usedEnergy, parameters).asBigDecimal(6); + BigDecimal ccd = Converter.energyToMicroCCD(usedEnergy, parameters).asBigDecimal(6); + System.out.println("Price of transaction is: " + usedEnergy + " = " + euros + " euros = " + ccd + " micro CCD"); + UpdateContract payload = UpdateContract.from(CONTRACT_ADDRESS, parameter); UpdateContractTransaction transaction = TransactionFactory.newUpdateContract() .sender(AccountAddress.from(SENDER_ADDRESS)) From f4a2d6c795a1018cb9a5c93d66246db0054bb380 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 19 Feb 2024 10:55:27 +0100 Subject: [PATCH 09/14] Adressed review comments --- .../java/com/concordium/sdk/Converter.java | 156 ------------------ .../com/concordium/sdk/CurrencyConverter.java | 137 +++++++++++++++ ...BigFraction.java => ConversionResult.java} | 48 ++++-- .../com/concordium/sdk/EnergyToCCDTest.java | 100 +++++------ 4 files changed, 219 insertions(+), 222 deletions(-) delete mode 100644 concordium-sdk/src/main/java/com/concordium/sdk/Converter.java create mode 100644 concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java rename concordium-sdk/src/main/java/com/concordium/sdk/types/{BigFraction.java => ConversionResult.java} (56%) diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java b/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java deleted file mode 100644 index 3444842a4..000000000 --- a/concordium-sdk/src/main/java/com/concordium/sdk/Converter.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.concordium.sdk; - -import com.concordium.sdk.requests.smartcontracts.Energy; -import com.concordium.sdk.responses.chainparameters.ChainParameters; -import com.concordium.sdk.transactions.CCDAmount; -import com.concordium.sdk.types.BigFraction; -import com.concordium.sdk.types.UInt64; - -import java.math.BigInteger; - -/** - * Utility class for converting between {@link CCDAmount}, {@link Energy} and Euros. - * Represents converted values using {@link BigFraction} to ensure precision. - */ -public class Converter { - - /** - * Converts {@link Energy} to euro using exchange rate from the provided {@link ChainParameters}. - * - * @param energy {@link Energy} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the euro value of {@link Energy}. - */ - public static BigFraction energyToEuro(Energy energy, ChainParameters parameters) { - BigFraction energyFraction = BigFraction.from(energy.getValue(), UInt64.from(1)); - return energyToEuro(energyFraction, parameters); - } - - /** - * Converts {@link BigFraction} representing {@link Energy} to euro using exchange rate from the provided {@link ChainParameters}. - * - * @param energy {@link BigFraction} representing an amount of {@link Energy} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the euro value of {@link Energy}. - */ - public static BigFraction energyToEuro(BigFraction energy, ChainParameters parameters) { - BigFraction euroPerEnergy = BigFraction.from(parameters.getEuroPerEnergy()); - return mult(energy, euroPerEnergy); - } - - /** - * Converts {@link Energy} to micro CCD using exchange rate from the provided {@link ChainParameters}. - * - * @param energy {@link Energy} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the micro CCD value of {@link Energy}. - */ - public static BigFraction energyToMicroCCD(Energy energy, ChainParameters parameters) { - BigFraction energyFraction = BigFraction.from(energy.getValue(), UInt64.from(1)); - return energyToMicroCCD(energyFraction, parameters); - } - - /** - * Converts {@link BigFraction} representing {@link Energy} to micro CCD using exchange rate from the provided {@link ChainParameters}. - * - * @param energy {@link BigFraction} representing an amount of {@link Energy} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the micro CCD value of {@link Energy}. - */ - public static BigFraction energyToMicroCCD(BigFraction energy, ChainParameters parameters) { - BigFraction euros = energyToEuro(energy, parameters); - return euroToMicroCCD(euros, parameters); - } - - /** - * Converts {@link CCDAmount} to euros using exchange rate from the provided {@link ChainParameters}. - * - * @param ccdAmount {@link CCDAmount} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the euro value of {@link CCDAmount}. - */ - public static BigFraction microCCDToEuro(CCDAmount ccdAmount, ChainParameters parameters) { - BigFraction ccd = BigFraction.from(ccdAmount.getValue(), UInt64.from(1)); - return microCCDToEuro(ccd, parameters); - } - - /** - * Converts {@link BigFraction} representing {@link CCDAmount} to euros using exchange rate from the provided {@link ChainParameters}. - * - * @param ccd {@link BigFraction} representing {@link CCDAmount} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the euro value of {@link CCDAmount}. - */ - public static BigFraction microCCDToEuro(BigFraction ccd, ChainParameters parameters) { - BigFraction microCCDPerEuro = BigFraction.from(parameters.getMicroCCDPerEuro()); - return div(ccd, microCCDPerEuro); - } - - /** - * Converts {@link CCDAmount} to energy using exchange rate from the provided {@link ChainParameters}. - * - * @param ccdAmount{@link CCDAmount} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the energy value of {@link CCDAmount}. - */ - public static BigFraction ccdToEnergy(CCDAmount ccdAmount, ChainParameters parameters) { - BigFraction ccd = BigFraction.from(ccdAmount.getValue(), UInt64.from(1)); - return ccdToEnergy(ccd, parameters); - } - - /** - * Converts {@link BigFraction} representing {@link CCDAmount} to energy using exchange rate from the provided {@link ChainParameters}. - * - * @param ccdAmount {@link BigFraction} representing {@link CCDAmount} to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the energy value of {@link CCDAmount}. - */ - public static BigFraction ccdToEnergy(BigFraction ccdAmount, ChainParameters parameters) { - BigFraction euros = microCCDToEuro(ccdAmount, parameters); - return euroToEnergy(euros, parameters); - } - - /** - * Converts {@link BigFraction} representing an amount of euros to micro CCD using exchange rate from the provided {@link ChainParameters}. - * - * @param euros {@link BigFraction} representing amount of euros to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the micro CCD value of the input. - */ - public static BigFraction euroToMicroCCD(BigFraction euros, ChainParameters parameters) { - BigFraction microCCDPerEuro = BigFraction.from(parameters.getMicroCCDPerEuro()); - return mult(euros, microCCDPerEuro); - } - - /** - * Converts {@link BigFraction} representing an amount of euros to energy using exchange rate from the provided {@link ChainParameters}. - * - * @param euros {@link BigFraction} representing amount of euros to convert. - * @param parameters {@link ChainParameters} with exchange rate used for conversion. - * @return {@link BigFraction} corresponding to the energy value of the input. - */ - public static BigFraction euroToEnergy(BigFraction euros, ChainParameters parameters) { - BigFraction euroPerEnergy = BigFraction.from(parameters.getEuroPerEnergy()); - return div(euros,euroPerEnergy); - } - - /** - * Helper function for multiplying {@link BigFraction}s used during conversions. - * Calculates a*c/b*d for input a/b, c/d. - */ - private static BigFraction mult(BigFraction a, BigFraction b) { - BigInteger numerator = a.getNumerator().multiply(b.getNumerator()); - BigInteger denominator = a.getDenominator().multiply(b.getDenominator()); - return BigFraction.from(numerator, denominator); - } - - /** - * Helper function for dividing {@link BigFraction}s used during conversions. - * Calculates a*d/b*c for input a/b, c/d. - */ - private static BigFraction div(BigFraction a, BigFraction b) { - BigInteger numerator = a.getNumerator().multiply(b.getDenominator()); - BigInteger denominator = a.getDenominator().multiply(b.getNumerator()); - return BigFraction.from(numerator, denominator); - } -} diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java b/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java new file mode 100644 index 000000000..8cede765d --- /dev/null +++ b/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java @@ -0,0 +1,137 @@ +package com.concordium.sdk; + +import com.concordium.sdk.requests.smartcontracts.Energy; +import com.concordium.sdk.responses.chainparameters.ChainParameters; +import com.concordium.sdk.transactions.CCDAmount; +import com.concordium.sdk.types.ConversionResult; +import com.concordium.sdk.types.UInt64; + +import static com.concordium.sdk.types.ConversionResult.*; + +/** + * Utility class for converting between {@link CCDAmount}, {@link Energy} and Euros. + * Represents converted values using {@link ConversionResult} to ensure precision. + */ +public class CurrencyConverter { + + /** + * Converts {@link Energy} to euro using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the euro value of {@link Energy}. + */ + public static ConversionResult energyToEuro(Energy energy, ChainParameters parameters) { + ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); + return energyToEuro(energyFraction, parameters); + } + + /** + * Converts {@link ConversionResult} representing {@link Energy} to euro using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link ConversionResult} representing an amount of {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the euro value of {@link Energy}. + */ + public static ConversionResult energyToEuro(ConversionResult energy, ChainParameters parameters) { + ConversionResult euroPerEnergy = from(parameters.getEuroPerEnergy()); + return energy.mult(euroPerEnergy); + } + + /** + * Converts {@link Energy} to micro CCD using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the micro CCD value of {@link Energy}. + */ + public static ConversionResult energyToMicroCCD(Energy energy, ChainParameters parameters) { + ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); + return energyToMicroCCD(energyFraction, parameters); + } + + /** + * Converts {@link ConversionResult} representing {@link Energy} to micro CCD using exchange rate from the provided {@link ChainParameters}. + * + * @param energy {@link ConversionResult} representing an amount of {@link Energy} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the micro CCD value of {@link Energy}. + */ + public static ConversionResult energyToMicroCCD(ConversionResult energy, ChainParameters parameters) { + ConversionResult euros = energyToEuro(energy, parameters); + return euroToMicroCCD(euros, parameters); + } + + /** + * Converts {@link CCDAmount} to euros using exchange rate from the provided {@link ChainParameters}. + * + * @param ccdAmount {@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the euro value of {@link CCDAmount}. + */ + public static ConversionResult microCCDToEuro(CCDAmount ccdAmount, ChainParameters parameters) { + ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); + return microCCDToEuro(ccd, parameters); + } + + /** + * Converts {@link ConversionResult} representing {@link CCDAmount} to euros using exchange rate from the provided {@link ChainParameters}. + * + * @param ccd {@link ConversionResult} representing {@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the euro value of {@link CCDAmount}. + */ + public static ConversionResult microCCDToEuro(ConversionResult ccd, ChainParameters parameters) { + ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); + return ccd.div(microCCDPerEuro); + } + + /** + * Converts {@link CCDAmount} to energy using exchange rate from the provided {@link ChainParameters}. + * + * @param ccdAmount{@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the energy value of {@link CCDAmount}. + */ + public static ConversionResult ccdToEnergy(CCDAmount ccdAmount, ChainParameters parameters) { + ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); + return ccdToEnergy(ccd, parameters); + } + + /** + * Converts {@link ConversionResult} representing {@link CCDAmount} to energy using exchange rate from the provided {@link ChainParameters}. + * + * @param ccdAmount {@link ConversionResult} representing {@link CCDAmount} to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the energy value of {@link CCDAmount}. + */ + public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, ChainParameters parameters) { + ConversionResult euros = microCCDToEuro(ccdAmount, parameters); + return euroToEnergy(euros, parameters); + } + + /** + * Converts {@link ConversionResult} representing an amount of euros to micro CCD using exchange rate from the provided {@link ChainParameters}. + * + * @param euros {@link ConversionResult} representing amount of euros to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the micro CCD value of the input. + */ + public static ConversionResult euroToMicroCCD(ConversionResult euros, ChainParameters parameters) { + ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); + return euros.mult(microCCDPerEuro); + } + + /** + * Converts {@link ConversionResult} representing an amount of euros to energy using exchange rate from the provided {@link ChainParameters}. + * + * @param euros {@link ConversionResult} representing amount of euros to convert. + * @param parameters {@link ChainParameters} with exchange rate used for conversion. + * @return {@link ConversionResult} corresponding to the energy value of the input. + */ + public static ConversionResult euroToEnergy(ConversionResult euros, ChainParameters parameters) { + ConversionResult euroPerEnergy = from(parameters.getEuroPerEnergy()); + return euros.div(euroPerEnergy); + } + +} diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java b/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java similarity index 56% rename from concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java rename to concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java index a3b3fbdad..308caabe3 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/types/BigFraction.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java @@ -1,6 +1,6 @@ package com.concordium.sdk.types; -import com.concordium.sdk.Converter; +import com.concordium.sdk.CurrencyConverter; import com.concordium.sdk.requests.smartcontracts.Energy; import com.concordium.sdk.responses.Fraction; import com.concordium.sdk.transactions.CCDAmount; @@ -12,12 +12,13 @@ import java.math.RoundingMode; /** - * For representing fractions with large numerators or denominators. Used in {@link Converter} to convert to/from {@link CCDAmount} and {@link Energy}. - * Use {@link BigFraction#asBigDecimal(int)} to get numeric value of the fraction. + * For representing fractions with large numerators or denominators. Used in {@link CurrencyConverter} to convert to/from {@link CCDAmount} and {@link Energy}. + * Use {@link ConversionResult#asBigDecimal(int)} to get numeric value of the fraction. */ @Getter @Builder -public class BigFraction { + +public class ConversionResult{ /** * Numerator of the fraction. @@ -28,17 +29,22 @@ public class BigFraction { */ private BigInteger denominator; - public static BigFraction from(BigInteger numerator, BigInteger denominator) { - return new BigFraction(numerator, denominator); + public static ConversionResult from(BigInteger numerator, BigInteger denominator) { + return new ConversionResult(numerator, denominator); } - public static BigFraction from(UInt64 numerator, UInt64 denominator) { - return new BigFraction(new BigInteger(numerator.toString()), new BigInteger(denominator.toString())); + public static ConversionResult from(UInt64 numerator, UInt64 denominator) { + return from(numerator.toString(),denominator.toString()); } - public static BigFraction from(Fraction fraction) { + public static ConversionResult from(Fraction fraction) { return from(fraction.getNumerator(),fraction.getDenominator()); } + + public static ConversionResult from(String numerator, String denominator) { + return from(new BigInteger(numerator), new BigInteger(denominator)); + } + @Override public String toString() { return this.numerator + "/" + this.denominator; @@ -69,6 +75,26 @@ public BigDecimal asBigDecimal(int precision, RoundingMode roundingMode) { return numerator.divide(denominator, precision, roundingMode); } + /** + * Multiplies {@link ConversionResult}s. + * Calculates a*c/b*d for input a/b, c/d. + */ + public ConversionResult mult(ConversionResult other) { + BigInteger numerator = this.getNumerator().multiply(other.getNumerator()); + BigInteger denominator = this.getDenominator().multiply(other.getDenominator()); + return ConversionResult.from(numerator, denominator); + } + + /** + * Helper function for dividing {@link ConversionResult}s used during conversions. + * Calculates a*d/b*c for input a/b, c/d. + */ + public ConversionResult div(ConversionResult other) { + BigInteger numerator = this.getNumerator().multiply(other.getDenominator()); + BigInteger denominator = this.getDenominator().multiply(other.getNumerator()); + return ConversionResult.from(numerator, denominator); + } + @Override public boolean equals(Object o) { @@ -76,11 +102,11 @@ public boolean equals(Object o) { return true; } - if (!(o instanceof BigFraction)) { + if (!(o instanceof ConversionResult)) { return false; } - BigFraction otherFraction = (BigFraction) o; + ConversionResult otherFraction = (ConversionResult) o; // Comparison done using cross multiplication. a * d = b * c => a/b = c/d BigInteger ad = this.numerator.multiply(otherFraction.denominator); diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java index bb6db87dd..1ee8b5146 100644 --- a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java +++ b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java @@ -4,12 +4,11 @@ import com.concordium.sdk.responses.Fraction; import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.transactions.CCDAmount; -import com.concordium.sdk.types.BigFraction; +import com.concordium.sdk.types.ConversionResult; import com.concordium.sdk.types.UInt64; import lombok.SneakyThrows; import org.junit.Test; -import java.math.BigInteger; import java.util.ArrayList; import java.util.List; @@ -28,9 +27,9 @@ public class EnergyToCCDTest { private static final CCDAmount CCD_AMOUNT = CCDAmount.fromMicro(CCD_LONG); private static final Energy ENERGY = Energy.from(UInt64.from(ENERGY_LONG)); - private static final BigFraction CCD_FRACTION = BigFraction.from(CCD_AMOUNT.getValue(), UInt64.from(1)); - private static final BigFraction ENERGY_FRACTION = BigFraction.from(ENERGY.getValue(), UInt64.from(1)); - private static final BigFraction EURO_FRACTION = BigFraction.from(UInt64.from(10), UInt64.from(1)); + private static final ConversionResult CCD_FRACTION = ConversionResult.from(CCD_AMOUNT.getValue(), UInt64.from(1)); + private static final ConversionResult ENERGY_FRACTION = ConversionResult.from(ENERGY.getValue(), UInt64.from(1)); + private static final ConversionResult EURO_FRACTION = ConversionResult.from(UInt64.from(10), UInt64.from(1)); // Euro per energy doesn't change value and isn't nearly as big so can use same value for tests. private static final Fraction EURO_PER_ENERGY = new Fraction(UInt64.from("1"), UInt64.from("1100000")); @@ -89,15 +88,15 @@ public void testShouldBePrecise() { } private void energyToCCD(ChainParameters parameters) { - BigFraction ccdFromEnergy = Converter.energyToMicroCCD(ENERGY, parameters); - BigFraction ccdFromEnergyFraction = Converter.energyToMicroCCD(ENERGY_FRACTION, parameters); - // Both conversions receive same result + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, parameters); + ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(ENERGY_FRACTION, parameters); + // Both conversions yield same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); - BigFraction energyFromCCD = Converter.ccdToEnergy(ccdFromEnergy, parameters); - BigFraction energyFromCCDFraction = Converter.ccdToEnergy(ccdFromEnergyFraction, parameters); + ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(ccdFromEnergy, parameters); + ConversionResult energyFromCCDFraction = CurrencyConverter.ccdToEnergy(ccdFromEnergyFraction, parameters); - // Converting back receives same result + // Converting back yields same result assertEquals(energyFromCCD, energyFromCCDFraction); // Converting back is precise @@ -105,111 +104,102 @@ private void energyToCCD(ChainParameters parameters) { } private void energyToEuro(ChainParameters parameters) { - BigFraction euroFromEnergy = Converter.energyToEuro(ENERGY, parameters); - BigFraction euroFromEnergyFraction = Converter.energyToEuro(ENERGY_FRACTION, parameters); - // Both conversions receive same result + ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(ENERGY, parameters); + ConversionResult euroFromEnergyFraction = CurrencyConverter.energyToEuro(ENERGY_FRACTION, parameters); + // Both conversions yield same result assertEquals(euroFromEnergy, euroFromEnergyFraction); - BigFraction energyFromEuro = Converter.euroToEnergy(euroFromEnergy, parameters); - BigFraction energyFromEuroFraction = Converter.euroToEnergy(euroFromEnergyFraction, parameters); + ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(euroFromEnergy, parameters); + ConversionResult energyFromEuroFraction = CurrencyConverter.euroToEnergy(euroFromEnergyFraction, parameters); - // Converting back receives same result + // Converting back yields same result assertEquals(energyFromEuro, energyFromEuroFraction); // Converting back is precise assertEquals(energyFromEuro, ENERGY_FRACTION); } private void ccdToEnergy(ChainParameters parameters) { - BigFraction energyFromCCD = Converter.ccdToEnergy(CCD_AMOUNT, parameters); - BigFraction energyFromCCDFraction = Converter.ccdToEnergy(CCD_FRACTION, parameters); + ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(CCD_AMOUNT, parameters); + ConversionResult energyFromCCDFraction = CurrencyConverter.ccdToEnergy(CCD_FRACTION, parameters); - // Both conversions receive same result + // Both conversions yield same result assertEquals(energyFromCCD, energyFromCCDFraction); - BigFraction ccdFromEnergy = Converter.energyToMicroCCD(energyFromCCD, parameters); - BigFraction ccdFromEnergyFraction = Converter.energyToMicroCCD(energyFromCCDFraction, parameters); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(energyFromCCD, parameters); + ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(energyFromCCDFraction, parameters); - // Converting back receives same result + // Converting back yields same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); // Converting back is precise assertEquals(ccdFromEnergy, CCD_FRACTION); } private void ccdToEuro(ChainParameters parameters) { - BigFraction euroFromCCD = Converter.microCCDToEuro(CCD_AMOUNT, parameters); - BigFraction euroFromCCDFraction = Converter.microCCDToEuro(CCD_FRACTION, parameters); - // Both conversions receive same result + ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(CCD_AMOUNT, parameters); + ConversionResult euroFromCCDFraction = CurrencyConverter.microCCDToEuro(CCD_FRACTION, parameters); + // Both conversions yield same result assertEquals(euroFromCCD,euroFromCCDFraction); - BigFraction ccdFromEuro = Converter.euroToMicroCCD(euroFromCCD, parameters); - BigFraction ccdFromEuroFraction = Converter.euroToMicroCCD(euroFromCCDFraction, parameters); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(euroFromCCD, parameters); + ConversionResult ccdFromEuroFraction = CurrencyConverter.euroToMicroCCD(euroFromCCDFraction, parameters); - // Converting back receives same result + // Converting back yields same result assertEquals(ccdFromEuro, ccdFromEuroFraction); // Converting back is precise assertEquals(ccdFromEuro, CCD_FRACTION); } private void euroToEnergy(ChainParameters parameters) { - BigFraction energyFromEuro = Converter.euroToEnergy(EURO_FRACTION, parameters); - BigFraction euroFromEnergy = Converter.energyToEuro(energyFromEuro, parameters); + ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(EURO_FRACTION, parameters); + ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(energyFromEuro, parameters); // Conversions are precise assertEquals(euroFromEnergy, EURO_FRACTION); } private void euroToCCD(ChainParameters parameters) { - BigFraction ccdFromEuro = Converter.euroToMicroCCD(EURO_FRACTION, parameters); - BigFraction euroFromCCD = Converter.microCCDToEuro(ccdFromEuro, parameters); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, parameters); + ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(ccdFromEuro, parameters); // Conversions are precise assertEquals(euroFromCCD, EURO_FRACTION); } /** - * Asserts that the calculations performed when using PARAM_1 gives the correct result. + * Asserts that the calculations performed when using PARAM_1 yield the correct result. */ @Test public void testActualValues() { // EURO_PER_ENERGY * ENERGY = 1/1100000×10000 = 1/110 - BigFraction expectedEuroFromEnergy = frac("1", "110"); - BigFraction euroFromEnergy = Converter.energyToEuro(ENERGY, PARAM_1); + ConversionResult expectedEuroFromEnergy = ConversionResult.from("1", "110"); + ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(ENERGY, PARAM_1); assertEquals(expectedEuroFromEnergy, euroFromEnergy); // MICRO_CCD_PER_EURO_1 * EURO = 16626124143116419072/78228883861 * 10 = 166261241431164190720/78228883861 - BigFraction expectedCCDFromEuro = frac("166261241431164190720","78228883861"); - BigFraction ccdFromEuro = Converter.euroToMicroCCD(EURO_FRACTION, PARAM_1); + ConversionResult expectedCCDFromEuro = ConversionResult.from("166261241431164190720","78228883861"); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, PARAM_1); assertEquals(expectedCCDFromEuro, ccdFromEuro); // EURO_PER_ENERGY * ENERGY * MICRO_CCD_PER_EURO_1 = 1/110 * 16626124143116419072/78228883861 = 8313062071558209536/4302588612355 - BigFraction expectedCCDFromEnergy = frac("8313062071558209536", "4302588612355"); - BigFraction ccdFromEnergy = Converter.energyToMicroCCD(ENERGY, PARAM_1); + ConversionResult expectedCCDFromEnergy = ConversionResult.from("8313062071558209536", "4302588612355"); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, PARAM_1); assertEquals(expectedCCDFromEnergy, ccdFromEnergy); // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 = 1000000 / (16626124143116419072/78228883861) = 1222326310328125/259783189736194048 - BigFraction expectedEuroFromCCD = frac("1222326310328125", "259783189736194048"); - BigFraction euroFromCCD = Converter.microCCDToEuro(CCD_AMOUNT, PARAM_1); + ConversionResult expectedEuroFromCCD = ConversionResult.from("1222326310328125", "259783189736194048"); + ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(CCD_AMOUNT, PARAM_1); assertEquals(expectedEuroFromCCD, euroFromCCD); // EUROS / EURO_PER_ENERGY = 10 / (1/1100000) = 11000000 - BigFraction expectedEnergyFromEuro = frac("11000000", "1"); - BigFraction energyFromEuro = Converter.euroToEnergy(EURO_FRACTION, PARAM_1); + ConversionResult expectedEnergyFromEuro = ConversionResult.from("11000000", "1"); + ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(EURO_FRACTION, PARAM_1); assertEquals(expectedEnergyFromEuro, energyFromEuro); // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 / EUROS_PER_ENERGY = // (1000000 / (16626124143116419072/78228883861)) / (1/1100000) = // 42017466917529296875/8118224679256064 - BigFraction expectedEnergyFromCCD = frac("42017466917529296875", "8118224679256064"); - BigFraction energyFromCCD = Converter.ccdToEnergy(CCD_AMOUNT, PARAM_1); + ConversionResult expectedEnergyFromCCD = ConversionResult.from("42017466917529296875", "8118224679256064"); + ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(CCD_AMOUNT, PARAM_1); assertEquals(expectedEnergyFromCCD, energyFromCCD); } - private BigFraction frac(String a, String b) { - return BigFraction.from(new BigInteger(a),new BigInteger(b)); - } - - - - - - } From b707f59f078a4f04d5077608cd08f4a78e087e87 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 19 Feb 2024 13:38:15 +0100 Subject: [PATCH 10/14] Extended ConversionResult with phantom types to prevent faulty conversions --- .../contractexample/cis2nft/Cis2Nft.java | 6 +- .../contractexample/wccd/Cis2WCCD.java | 6 +- .../com/concordium/sdk/CurrencyConverter.java | 42 +++++------ .../sdk/types/ConversionResult.java | 48 +++++++----- .../com/concordium/sdk/EnergyToCCDTest.java | 73 ++++++++++--------- 5 files changed, 96 insertions(+), 79 deletions(-) diff --git a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java index a92187cfb..658e21f9b 100644 --- a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java +++ b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/cis2nft/Cis2Nft.java @@ -2,7 +2,7 @@ import com.concordium.sdk.ClientV2; import com.concordium.sdk.Connection; -import com.concordium.sdk.Converter; +import com.concordium.sdk.CurrencyConverter; import com.concordium.sdk.crypto.ed25519.ED25519SecretKey; import com.concordium.sdk.exceptions.ClientInitializationException; import com.concordium.sdk.requests.AccountQuery; @@ -143,8 +143,8 @@ private void handleMethod(ClientV2 client, Nonce nonce, SchemaParameter paramete Energy usedEnergy = invokeInstanceResult.getUsedEnergy(); ChainParameters parameters = client.getChainParameters(BlockQuery.LAST_FINAL); // Convert to Euro and CCD using ChainParameters from the best block and utility methods in the Converter class. - BigDecimal euros = Converter.energyToEuro(usedEnergy, parameters).asBigDecimal(6); - BigDecimal ccd = Converter.energyToMicroCCD(usedEnergy, parameters).asBigDecimal(6); + BigDecimal euros = CurrencyConverter.energyToEuro(usedEnergy, parameters).asBigDecimal(6); + BigDecimal ccd = CurrencyConverter.energyToMicroCCD(usedEnergy, parameters).asBigDecimal(6); System.out.println("Price of transaction is: " + usedEnergy + " = " + euros + " euros = " + ccd + " micro CCD"); UpdateContract payload = UpdateContract.from(CONTRACT_ADDRESS, parameter); diff --git a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java index 4e1c7f62b..7c2b44329 100644 --- a/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java +++ b/concordium-sdk-examples/src/main/java/com/concordium/sdk/examples/contractexample/wccd/Cis2WCCD.java @@ -2,7 +2,7 @@ import com.concordium.sdk.ClientV2; import com.concordium.sdk.Connection; -import com.concordium.sdk.Converter; +import com.concordium.sdk.CurrencyConverter; import com.concordium.sdk.crypto.ed25519.ED25519SecretKey; import com.concordium.sdk.requests.AccountQuery; import com.concordium.sdk.requests.BlockQuery; @@ -162,8 +162,8 @@ private void handleMethod(ClientV2 client, Nonce nonce, SchemaParameter paramete Energy usedEnergy = invokeInstanceResult.getUsedEnergy(); ChainParameters parameters = client.getChainParameters(BlockQuery.LAST_FINAL); // Convert to Euro and CCD using ChainParameters from the best block and utility methods in the Converter class. - BigDecimal euros = Converter.energyToEuro(usedEnergy, parameters).asBigDecimal(6); - BigDecimal ccd = Converter.energyToMicroCCD(usedEnergy, parameters).asBigDecimal(6); + BigDecimal euros = CurrencyConverter.energyToEuro(usedEnergy, parameters).asBigDecimal(6); + BigDecimal ccd = CurrencyConverter.energyToMicroCCD(usedEnergy, parameters).asBigDecimal(6); System.out.println("Price of transaction is: " + usedEnergy + " = " + euros + " euros = " + ccd + " micro CCD"); UpdateContract payload = UpdateContract.from(CONTRACT_ADDRESS, parameter); diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java b/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java index 8cede765d..847679149 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java @@ -21,8 +21,8 @@ public class CurrencyConverter { * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the euro value of {@link Energy}. */ - public static ConversionResult energyToEuro(Energy energy, ChainParameters parameters) { - ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); + public static ConversionResult energyToEuro(Energy energy, ChainParameters parameters) { + ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); return energyToEuro(energyFraction, parameters); } @@ -33,8 +33,8 @@ public static ConversionResult energyToEuro(Energy energy, ChainParameters param * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the euro value of {@link Energy}. */ - public static ConversionResult energyToEuro(ConversionResult energy, ChainParameters parameters) { - ConversionResult euroPerEnergy = from(parameters.getEuroPerEnergy()); + public static ConversionResult energyToEuro(ConversionResult energy, ChainParameters parameters) { + ConversionResult euroPerEnergy = from(parameters.getEuroPerEnergy()); return energy.mult(euroPerEnergy); } @@ -45,8 +45,8 @@ public static ConversionResult energyToEuro(ConversionResult energy, ChainParame * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the micro CCD value of {@link Energy}. */ - public static ConversionResult energyToMicroCCD(Energy energy, ChainParameters parameters) { - ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); + public static ConversionResult energyToMicroCCD(Energy energy, ChainParameters parameters) { + ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); return energyToMicroCCD(energyFraction, parameters); } @@ -57,8 +57,8 @@ public static ConversionResult energyToMicroCCD(Energy energy, ChainParameters p * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the micro CCD value of {@link Energy}. */ - public static ConversionResult energyToMicroCCD(ConversionResult energy, ChainParameters parameters) { - ConversionResult euros = energyToEuro(energy, parameters); + public static ConversionResult energyToMicroCCD(ConversionResult energy, ChainParameters parameters) { + ConversionResult euros = energyToEuro(energy, parameters); return euroToMicroCCD(euros, parameters); } @@ -69,8 +69,8 @@ public static ConversionResult energyToMicroCCD(ConversionResult energy, ChainPa * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the euro value of {@link CCDAmount}. */ - public static ConversionResult microCCDToEuro(CCDAmount ccdAmount, ChainParameters parameters) { - ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); + public static ConversionResult microCCDToEuro(CCDAmount ccdAmount, ChainParameters parameters) { + ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); return microCCDToEuro(ccd, parameters); } @@ -81,8 +81,8 @@ public static ConversionResult microCCDToEuro(CCDAmount ccdAmount, ChainParamete * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the euro value of {@link CCDAmount}. */ - public static ConversionResult microCCDToEuro(ConversionResult ccd, ChainParameters parameters) { - ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); + public static ConversionResult microCCDToEuro(ConversionResult ccd, ChainParameters parameters) { + ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); return ccd.div(microCCDPerEuro); } @@ -93,8 +93,8 @@ public static ConversionResult microCCDToEuro(ConversionResult ccd, ChainParamet * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the energy value of {@link CCDAmount}. */ - public static ConversionResult ccdToEnergy(CCDAmount ccdAmount, ChainParameters parameters) { - ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); + public static ConversionResult ccdToEnergy(CCDAmount ccdAmount, ChainParameters parameters) { + ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); return ccdToEnergy(ccd, parameters); } @@ -105,8 +105,8 @@ public static ConversionResult ccdToEnergy(CCDAmount ccdAmount, ChainParameters * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the energy value of {@link CCDAmount}. */ - public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, ChainParameters parameters) { - ConversionResult euros = microCCDToEuro(ccdAmount, parameters); + public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, ChainParameters parameters) { + ConversionResult euros = microCCDToEuro(ccdAmount, parameters); return euroToEnergy(euros, parameters); } @@ -117,20 +117,20 @@ public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, ChainPara * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the micro CCD value of the input. */ - public static ConversionResult euroToMicroCCD(ConversionResult euros, ChainParameters parameters) { - ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); + public static ConversionResult euroToMicroCCD(ConversionResult euros, ChainParameters parameters) { + ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); return euros.mult(microCCDPerEuro); } /** * Converts {@link ConversionResult} representing an amount of euros to energy using exchange rate from the provided {@link ChainParameters}. - * + *† * @param euros {@link ConversionResult} representing amount of euros to convert. * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the energy value of the input. */ - public static ConversionResult euroToEnergy(ConversionResult euros, ChainParameters parameters) { - ConversionResult euroPerEnergy = from(parameters.getEuroPerEnergy()); + public static ConversionResult euroToEnergy(ConversionResult euros, ChainParameters parameters) { + ConversionResult euroPerEnergy = from(parameters.getEuroPerEnergy()); return euros.div(euroPerEnergy); } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java b/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java index 308caabe3..f87051dd5 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java @@ -4,7 +4,6 @@ import com.concordium.sdk.requests.smartcontracts.Energy; import com.concordium.sdk.responses.Fraction; import com.concordium.sdk.transactions.CCDAmount; -import lombok.Builder; import lombok.Getter; import java.math.BigDecimal; @@ -14,35 +13,50 @@ /** * For representing fractions with large numerators or denominators. Used in {@link CurrencyConverter} to convert to/from {@link CCDAmount} and {@link Energy}. * Use {@link ConversionResult#asBigDecimal(int)} to get numeric value of the fraction. + * Type parameter prevents faulty usage of conversion functions in {@link CurrencyConverter}. */ @Getter -@Builder +public class ConversionResult{ -public class ConversionResult{ + private ConversionResult(BigInteger numerator, BigInteger denominator) { + this.numerator = numerator; + this.denominator = denominator; + } + + + public interface ConversionResultType {} + + public static final class CCD implements ConversionResultType {} + + public static final class NRG implements ConversionResultType {} + + public static final class EUR implements ConversionResultType {} + + public static final class ConversionRate implements ConversionResultType {} /** * Numerator of the fraction. */ - private BigInteger numerator; + private final BigInteger numerator; /** * Denominator of the fraction. */ - private BigInteger denominator; + private final BigInteger denominator; - public static ConversionResult from(BigInteger numerator, BigInteger denominator) { - return new ConversionResult(numerator, denominator); + public static ConversionResult from(BigInteger numerator, BigInteger denominator) { + return new ConversionResult<>(numerator, denominator); } - public static ConversionResult from(UInt64 numerator, UInt64 denominator) { - return from(numerator.toString(),denominator.toString()); + public static ConversionResult from(String numerator, String denominator) { + return from(new BigInteger(numerator), new BigInteger(denominator)); } - public static ConversionResult from(Fraction fraction) { - return from(fraction.getNumerator(),fraction.getDenominator()); + public static ConversionResult from(UInt64 numerator, UInt64 denominator) { + return from(numerator.toString(),denominator.toString()); } - public static ConversionResult from(String numerator, String denominator) { - return from(new BigInteger(numerator), new BigInteger(denominator)); + public static ConversionResult from(Fraction fraction) { + return from(fraction.getNumerator(),fraction.getDenominator()); } @Override @@ -79,17 +93,17 @@ public BigDecimal asBigDecimal(int precision, RoundingMode roundingMode) { * Multiplies {@link ConversionResult}s. * Calculates a*c/b*d for input a/b, c/d. */ - public ConversionResult mult(ConversionResult other) { + public ConversionResult mult(ConversionResult other) { BigInteger numerator = this.getNumerator().multiply(other.getNumerator()); BigInteger denominator = this.getDenominator().multiply(other.getDenominator()); return ConversionResult.from(numerator, denominator); } /** - * Helper function for dividing {@link ConversionResult}s used during conversions. + * Divides {@link ConversionResult}s. * Calculates a*d/b*c for input a/b, c/d. */ - public ConversionResult div(ConversionResult other) { + public ConversionResult div(ConversionResult other) { BigInteger numerator = this.getNumerator().multiply(other.getDenominator()); BigInteger denominator = this.getDenominator().multiply(other.getNumerator()); return ConversionResult.from(numerator, denominator); @@ -106,7 +120,7 @@ public boolean equals(Object o) { return false; } - ConversionResult otherFraction = (ConversionResult) o; + ConversionResult otherFraction = (ConversionResult) o; // Comparison done using cross multiplication. a * d = b * c => a/b = c/d BigInteger ad = this.numerator.multiply(otherFraction.denominator); diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java index 1ee8b5146..a9663b841 100644 --- a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java +++ b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java @@ -5,6 +5,9 @@ import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.transactions.CCDAmount; import com.concordium.sdk.types.ConversionResult; +import com.concordium.sdk.types.ConversionResult.CCD; +import com.concordium.sdk.types.ConversionResult.EUR; +import com.concordium.sdk.types.ConversionResult.NRG; import com.concordium.sdk.types.UInt64; import lombok.SneakyThrows; import org.junit.Test; @@ -27,9 +30,9 @@ public class EnergyToCCDTest { private static final CCDAmount CCD_AMOUNT = CCDAmount.fromMicro(CCD_LONG); private static final Energy ENERGY = Energy.from(UInt64.from(ENERGY_LONG)); - private static final ConversionResult CCD_FRACTION = ConversionResult.from(CCD_AMOUNT.getValue(), UInt64.from(1)); - private static final ConversionResult ENERGY_FRACTION = ConversionResult.from(ENERGY.getValue(), UInt64.from(1)); - private static final ConversionResult EURO_FRACTION = ConversionResult.from(UInt64.from(10), UInt64.from(1)); + private static final ConversionResult CCD_FRACTION = ConversionResult.from(CCD_AMOUNT.getValue(), UInt64.from(1)); + private static final ConversionResult ENERGY_FRACTION = ConversionResult.from(ENERGY.getValue(), UInt64.from(1)); + private static final ConversionResult EURO_FRACTION = ConversionResult.from(UInt64.from(10), UInt64.from(1)); // Euro per energy doesn't change value and isn't nearly as big so can use same value for tests. private static final Fraction EURO_PER_ENERGY = new Fraction(UInt64.from("1"), UInt64.from("1100000")); @@ -88,13 +91,13 @@ public void testShouldBePrecise() { } private void energyToCCD(ChainParameters parameters) { - ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, parameters); - ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(ENERGY_FRACTION, parameters); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, parameters); + ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(ENERGY_FRACTION, parameters); // Both conversions yield same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); - ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(ccdFromEnergy, parameters); - ConversionResult energyFromCCDFraction = CurrencyConverter.ccdToEnergy(ccdFromEnergyFraction, parameters); + ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(ccdFromEnergy, parameters); + ConversionResult energyFromCCDFraction = CurrencyConverter.ccdToEnergy(ccdFromEnergyFraction, parameters); // Converting back yields same result assertEquals(energyFromCCD, energyFromCCDFraction); @@ -104,13 +107,13 @@ private void energyToCCD(ChainParameters parameters) { } private void energyToEuro(ChainParameters parameters) { - ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(ENERGY, parameters); - ConversionResult euroFromEnergyFraction = CurrencyConverter.energyToEuro(ENERGY_FRACTION, parameters); + ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(ENERGY, parameters); + ConversionResult euroFromEnergyFraction = CurrencyConverter.energyToEuro(ENERGY_FRACTION, parameters); // Both conversions yield same result assertEquals(euroFromEnergy, euroFromEnergyFraction); - ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(euroFromEnergy, parameters); - ConversionResult energyFromEuroFraction = CurrencyConverter.euroToEnergy(euroFromEnergyFraction, parameters); + ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(euroFromEnergy, parameters); + ConversionResult energyFromEuroFraction = CurrencyConverter.euroToEnergy(euroFromEnergyFraction, parameters); // Converting back yields same result assertEquals(energyFromEuro, energyFromEuroFraction); @@ -119,14 +122,14 @@ private void energyToEuro(ChainParameters parameters) { assertEquals(energyFromEuro, ENERGY_FRACTION); } private void ccdToEnergy(ChainParameters parameters) { - ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(CCD_AMOUNT, parameters); - ConversionResult energyFromCCDFraction = CurrencyConverter.ccdToEnergy(CCD_FRACTION, parameters); + ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(CCD_AMOUNT, parameters); + ConversionResult energyFromCCDFraction = CurrencyConverter.ccdToEnergy(CCD_FRACTION, parameters); // Both conversions yield same result assertEquals(energyFromCCD, energyFromCCDFraction); - ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(energyFromCCD, parameters); - ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(energyFromCCDFraction, parameters); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(energyFromCCD, parameters); + ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(energyFromCCDFraction, parameters); // Converting back yields same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); @@ -135,13 +138,13 @@ private void ccdToEnergy(ChainParameters parameters) { assertEquals(ccdFromEnergy, CCD_FRACTION); } private void ccdToEuro(ChainParameters parameters) { - ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(CCD_AMOUNT, parameters); - ConversionResult euroFromCCDFraction = CurrencyConverter.microCCDToEuro(CCD_FRACTION, parameters); + ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(CCD_AMOUNT, parameters); + ConversionResult euroFromCCDFraction = CurrencyConverter.microCCDToEuro(CCD_FRACTION, parameters); // Both conversions yield same result assertEquals(euroFromCCD,euroFromCCDFraction); - ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(euroFromCCD, parameters); - ConversionResult ccdFromEuroFraction = CurrencyConverter.euroToMicroCCD(euroFromCCDFraction, parameters); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(euroFromCCD, parameters); + ConversionResult ccdFromEuroFraction = CurrencyConverter.euroToMicroCCD(euroFromCCDFraction, parameters); // Converting back yields same result assertEquals(ccdFromEuro, ccdFromEuroFraction); @@ -150,15 +153,15 @@ private void ccdToEuro(ChainParameters parameters) { assertEquals(ccdFromEuro, CCD_FRACTION); } private void euroToEnergy(ChainParameters parameters) { - ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(EURO_FRACTION, parameters); - ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(energyFromEuro, parameters); + ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(EURO_FRACTION, parameters); + ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(energyFromEuro, parameters); // Conversions are precise assertEquals(euroFromEnergy, EURO_FRACTION); } private void euroToCCD(ChainParameters parameters) { - ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, parameters); - ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(ccdFromEuro, parameters); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, parameters); + ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(ccdFromEuro, parameters); // Conversions are precise assertEquals(euroFromCCD, EURO_FRACTION); @@ -170,35 +173,35 @@ private void euroToCCD(ChainParameters parameters) { @Test public void testActualValues() { // EURO_PER_ENERGY * ENERGY = 1/1100000×10000 = 1/110 - ConversionResult expectedEuroFromEnergy = ConversionResult.from("1", "110"); - ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(ENERGY, PARAM_1); + ConversionResult expectedEuroFromEnergy = ConversionResult.from("1", "110"); + ConversionResult euroFromEnergy = CurrencyConverter.energyToEuro(ENERGY, PARAM_1); assertEquals(expectedEuroFromEnergy, euroFromEnergy); // MICRO_CCD_PER_EURO_1 * EURO = 16626124143116419072/78228883861 * 10 = 166261241431164190720/78228883861 - ConversionResult expectedCCDFromEuro = ConversionResult.from("166261241431164190720","78228883861"); - ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, PARAM_1); + ConversionResult expectedCCDFromEuro = ConversionResult.from("166261241431164190720","78228883861"); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, PARAM_1); assertEquals(expectedCCDFromEuro, ccdFromEuro); // EURO_PER_ENERGY * ENERGY * MICRO_CCD_PER_EURO_1 = 1/110 * 16626124143116419072/78228883861 = 8313062071558209536/4302588612355 - ConversionResult expectedCCDFromEnergy = ConversionResult.from("8313062071558209536", "4302588612355"); - ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, PARAM_1); + ConversionResult expectedCCDFromEnergy = ConversionResult.from("8313062071558209536", "4302588612355"); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, PARAM_1); assertEquals(expectedCCDFromEnergy, ccdFromEnergy); // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 = 1000000 / (16626124143116419072/78228883861) = 1222326310328125/259783189736194048 - ConversionResult expectedEuroFromCCD = ConversionResult.from("1222326310328125", "259783189736194048"); - ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(CCD_AMOUNT, PARAM_1); + ConversionResult expectedEuroFromCCD = ConversionResult.from("1222326310328125", "259783189736194048"); + ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(CCD_AMOUNT, PARAM_1); assertEquals(expectedEuroFromCCD, euroFromCCD); // EUROS / EURO_PER_ENERGY = 10 / (1/1100000) = 11000000 - ConversionResult expectedEnergyFromEuro = ConversionResult.from("11000000", "1"); - ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(EURO_FRACTION, PARAM_1); + ConversionResult expectedEnergyFromEuro = ConversionResult.from("11000000", "1"); + ConversionResult energyFromEuro = CurrencyConverter.euroToEnergy(EURO_FRACTION, PARAM_1); assertEquals(expectedEnergyFromEuro, energyFromEuro); // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 / EUROS_PER_ENERGY = // (1000000 / (16626124143116419072/78228883861)) / (1/1100000) = // 42017466917529296875/8118224679256064 - ConversionResult expectedEnergyFromCCD = ConversionResult.from("42017466917529296875", "8118224679256064"); - ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(CCD_AMOUNT, PARAM_1); + ConversionResult expectedEnergyFromCCD = ConversionResult.from("42017466917529296875", "8118224679256064"); + ConversionResult energyFromCCD = CurrencyConverter.ccdToEnergy(CCD_AMOUNT, PARAM_1); assertEquals(expectedEnergyFromCCD, energyFromCCD); } From 3ca45b8c41c11e22225081a1f8663a2d0c276e2d Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 19 Feb 2024 13:39:21 +0100 Subject: [PATCH 11/14] merge main --- concordium-base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concordium-base b/concordium-base index 23129b486..8024ceed0 160000 --- a/concordium-base +++ b/concordium-base @@ -1 +1 @@ -Subproject commit 23129b48624f8ca9fed57b167c88b31e7b7170d8 +Subproject commit 8024ceed057aeccee59f158a64cd108e35f2a5fc From f7db930e9a382af4a795b23dd600ef2579f68534 Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 19 Feb 2024 13:57:55 +0100 Subject: [PATCH 12/14] Update submodule --- crypto-jni/Cargo.lock | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crypto-jni/Cargo.lock b/crypto-jni/Cargo.lock index 87f9a9204..46aaed340 100644 --- a/crypto-jni/Cargo.lock +++ b/crypto-jni/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ [[package]] name = "concordium-contracts-common" -version = "9.0.0" +version = "8.1.1" dependencies = [ "base64", "bs58", @@ -397,7 +397,7 @@ dependencies = [ [[package]] name = "concordium_base" -version = "4.0.0" +version = "3.2.0" dependencies = [ "anyhow", "ark-bls12-381", @@ -1754,7 +1754,6 @@ version = "0.2.0" dependencies = [ "anyhow", "concordium_base", - "ed25519-dalek", "either", "hex", "key_derivation", From 20ca0b2fae901f221321bc005a81fd917daa423b Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Mon, 19 Feb 2024 14:08:24 +0100 Subject: [PATCH 13/14] Update concordium-base --- concordium-base | 2 +- crypto-jni/Cargo.lock | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/concordium-base b/concordium-base index 8024ceed0..23129b486 160000 --- a/concordium-base +++ b/concordium-base @@ -1 +1 @@ -Subproject commit 8024ceed057aeccee59f158a64cd108e35f2a5fc +Subproject commit 23129b48624f8ca9fed57b167c88b31e7b7170d8 diff --git a/crypto-jni/Cargo.lock b/crypto-jni/Cargo.lock index 46aaed340..87f9a9204 100644 --- a/crypto-jni/Cargo.lock +++ b/crypto-jni/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ [[package]] name = "concordium-contracts-common" -version = "8.1.1" +version = "9.0.0" dependencies = [ "base64", "bs58", @@ -397,7 +397,7 @@ dependencies = [ [[package]] name = "concordium_base" -version = "3.2.0" +version = "4.0.0" dependencies = [ "anyhow", "ark-bls12-381", @@ -1754,6 +1754,7 @@ version = "0.2.0" dependencies = [ "anyhow", "concordium_base", + "ed25519-dalek", "either", "hex", "key_derivation", From 81dd2330eb0962a212e342b6c507093248e4449c Mon Sep 17 00:00:00 2001 From: magnusbechwind Date: Wed, 28 Feb 2024 11:51:59 +0100 Subject: [PATCH 14/14] Addressed review comments --- .../com/concordium/sdk/CurrencyConverter.java | 14 +++++----- .../concordium/sdk/responses/Fraction.java | 4 +-- .../sdk/types/ConversionResult.java | 15 ++++++++--- .../com/concordium/sdk/EnergyToCCDTest.java | 26 +++++++++---------- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java b/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java index 847679149..a4f01669a 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/CurrencyConverter.java @@ -45,7 +45,7 @@ public static ConversionResult energyToEuro(ConversionResult energy, C * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the micro CCD value of {@link Energy}. */ - public static ConversionResult energyToMicroCCD(Energy energy, ChainParameters parameters) { + public static ConversionResult energyToMicroCCD(Energy energy, ChainParameters parameters) { ConversionResult energyFraction = from(energy.getValue(), UInt64.from(1)); return energyToMicroCCD(energyFraction, parameters); } @@ -57,7 +57,7 @@ public static ConversionResult energyToMicroCCD(Energy energy, ChainParamet * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the micro CCD value of {@link Energy}. */ - public static ConversionResult energyToMicroCCD(ConversionResult energy, ChainParameters parameters) { + public static ConversionResult energyToMicroCCD(ConversionResult energy, ChainParameters parameters) { ConversionResult euros = energyToEuro(energy, parameters); return euroToMicroCCD(euros, parameters); } @@ -70,7 +70,7 @@ public static ConversionResult energyToMicroCCD(ConversionResult energ * @return {@link ConversionResult} corresponding to the euro value of {@link CCDAmount}. */ public static ConversionResult microCCDToEuro(CCDAmount ccdAmount, ChainParameters parameters) { - ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); + ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); return microCCDToEuro(ccd, parameters); } @@ -81,7 +81,7 @@ public static ConversionResult microCCDToEuro(CCDAmount ccdAmount, ChainPar * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the euro value of {@link CCDAmount}. */ - public static ConversionResult microCCDToEuro(ConversionResult ccd, ChainParameters parameters) { + public static ConversionResult microCCDToEuro(ConversionResult ccd, ChainParameters parameters) { ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); return ccd.div(microCCDPerEuro); } @@ -94,7 +94,7 @@ public static ConversionResult microCCDToEuro(ConversionResult ccd, Ch * @return {@link ConversionResult} corresponding to the energy value of {@link CCDAmount}. */ public static ConversionResult ccdToEnergy(CCDAmount ccdAmount, ChainParameters parameters) { - ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); + ConversionResult ccd = from(ccdAmount.getValue(), UInt64.from(1)); return ccdToEnergy(ccd, parameters); } @@ -105,7 +105,7 @@ public static ConversionResult ccdToEnergy(CCDAmount ccdAmount, ChainParame * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the energy value of {@link CCDAmount}. */ - public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, ChainParameters parameters) { + public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, ChainParameters parameters) { ConversionResult euros = microCCDToEuro(ccdAmount, parameters); return euroToEnergy(euros, parameters); } @@ -117,7 +117,7 @@ public static ConversionResult ccdToEnergy(ConversionResult ccdAmount, * @param parameters {@link ChainParameters} with exchange rate used for conversion. * @return {@link ConversionResult} corresponding to the micro CCD value of the input. */ - public static ConversionResult euroToMicroCCD(ConversionResult euros, ChainParameters parameters) { + public static ConversionResult euroToMicroCCD(ConversionResult euros, ChainParameters parameters) { ConversionResult microCCDPerEuro = from(parameters.getMicroCCDPerEuro()); return euros.mult(microCCDPerEuro); } diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java index d859deb2f..9ba390379 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/responses/Fraction.java @@ -59,7 +59,7 @@ public double asDouble() { } /** - * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision i.e. the specified amount of decimal points. * Result is rounded using {@link RoundingMode#HALF_UP} * * @param precision how many decimals of precision. @@ -70,7 +70,7 @@ public BigDecimal asBigDecimal(int precision) { } /** - * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision i.e. the specified amount of decimal points. * Result is rounded using the provided {@link RoundingMode}. * * @param precision how many decimals of precision. diff --git a/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java b/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java index f87051dd5..6b921cac1 100644 --- a/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java +++ b/concordium-sdk/src/main/java/com/concordium/sdk/types/ConversionResult.java @@ -26,10 +26,19 @@ private ConversionResult(BigInteger numerator, BigInteger denominator) { public interface ConversionResultType {} - public static final class CCD implements ConversionResultType {} + /** + * Phantom type for {@link ConversionResult} indicating the result represents a {@link CCDAmount}. + */ + public static final class microCCD implements ConversionResultType {} + /** + * Phantom type for {@link ConversionResult} indicating the result represents an amount of {@link Energy} + */ public static final class NRG implements ConversionResultType {} + /** + * Phantom type for {@link ConversionResult} indicating the result represents an amount of Euros + */ public static final class EUR implements ConversionResultType {} public static final class ConversionRate implements ConversionResultType {} @@ -65,7 +74,7 @@ public String toString() { } /** - * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision i.e. the specified amount of decimal points. * Result is rounded using {@link RoundingMode#HALF_UP} * * @param precision how many decimals of precision. @@ -76,7 +85,7 @@ public BigDecimal asBigDecimal(int precision) { } /** - * Get the fraction as a {@link BigDecimal} value with the specified amount of precision. + * Get the fraction as a {@link BigDecimal} value with the specified amount of precision i.e. the specified amount of decimal points. * Result is rounded using the provided {@link RoundingMode}. * * @param precision how many decimals of precision. diff --git a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java index a9663b841..fc3fc27af 100644 --- a/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java +++ b/concordium-sdk/src/test/java/com/concordium/sdk/EnergyToCCDTest.java @@ -5,7 +5,7 @@ import com.concordium.sdk.responses.chainparameters.ChainParameters; import com.concordium.sdk.transactions.CCDAmount; import com.concordium.sdk.types.ConversionResult; -import com.concordium.sdk.types.ConversionResult.CCD; +import com.concordium.sdk.types.ConversionResult.microCCD; import com.concordium.sdk.types.ConversionResult.EUR; import com.concordium.sdk.types.ConversionResult.NRG; import com.concordium.sdk.types.UInt64; @@ -30,7 +30,7 @@ public class EnergyToCCDTest { private static final CCDAmount CCD_AMOUNT = CCDAmount.fromMicro(CCD_LONG); private static final Energy ENERGY = Energy.from(UInt64.from(ENERGY_LONG)); - private static final ConversionResult CCD_FRACTION = ConversionResult.from(CCD_AMOUNT.getValue(), UInt64.from(1)); + private static final ConversionResult CCD_FRACTION = ConversionResult.from(CCD_AMOUNT.getValue(), UInt64.from(1)); private static final ConversionResult ENERGY_FRACTION = ConversionResult.from(ENERGY.getValue(), UInt64.from(1)); private static final ConversionResult EURO_FRACTION = ConversionResult.from(UInt64.from(10), UInt64.from(1)); @@ -91,8 +91,8 @@ public void testShouldBePrecise() { } private void energyToCCD(ChainParameters parameters) { - ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, parameters); - ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(ENERGY_FRACTION, parameters); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, parameters); + ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(ENERGY_FRACTION, parameters); // Both conversions yield same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); @@ -128,8 +128,8 @@ private void ccdToEnergy(ChainParameters parameters) { // Both conversions yield same result assertEquals(energyFromCCD, energyFromCCDFraction); - ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(energyFromCCD, parameters); - ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(energyFromCCDFraction, parameters); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(energyFromCCD, parameters); + ConversionResult ccdFromEnergyFraction = CurrencyConverter.energyToMicroCCD(energyFromCCDFraction, parameters); // Converting back yields same result assertEquals(ccdFromEnergy, ccdFromEnergyFraction); @@ -143,8 +143,8 @@ private void ccdToEuro(ChainParameters parameters) { // Both conversions yield same result assertEquals(euroFromCCD,euroFromCCDFraction); - ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(euroFromCCD, parameters); - ConversionResult ccdFromEuroFraction = CurrencyConverter.euroToMicroCCD(euroFromCCDFraction, parameters); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(euroFromCCD, parameters); + ConversionResult ccdFromEuroFraction = CurrencyConverter.euroToMicroCCD(euroFromCCDFraction, parameters); // Converting back yields same result assertEquals(ccdFromEuro, ccdFromEuroFraction); @@ -160,7 +160,7 @@ private void euroToEnergy(ChainParameters parameters) { assertEquals(euroFromEnergy, EURO_FRACTION); } private void euroToCCD(ChainParameters parameters) { - ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, parameters); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, parameters); ConversionResult euroFromCCD = CurrencyConverter.microCCDToEuro(ccdFromEuro, parameters); // Conversions are precise @@ -178,13 +178,13 @@ public void testActualValues() { assertEquals(expectedEuroFromEnergy, euroFromEnergy); // MICRO_CCD_PER_EURO_1 * EURO = 16626124143116419072/78228883861 * 10 = 166261241431164190720/78228883861 - ConversionResult expectedCCDFromEuro = ConversionResult.from("166261241431164190720","78228883861"); - ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, PARAM_1); + ConversionResult expectedCCDFromEuro = ConversionResult.from("166261241431164190720","78228883861"); + ConversionResult ccdFromEuro = CurrencyConverter.euroToMicroCCD(EURO_FRACTION, PARAM_1); assertEquals(expectedCCDFromEuro, ccdFromEuro); // EURO_PER_ENERGY * ENERGY * MICRO_CCD_PER_EURO_1 = 1/110 * 16626124143116419072/78228883861 = 8313062071558209536/4302588612355 - ConversionResult expectedCCDFromEnergy = ConversionResult.from("8313062071558209536", "4302588612355"); - ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, PARAM_1); + ConversionResult expectedCCDFromEnergy = ConversionResult.from("8313062071558209536", "4302588612355"); + ConversionResult ccdFromEnergy = CurrencyConverter.energyToMicroCCD(ENERGY, PARAM_1); assertEquals(expectedCCDFromEnergy, ccdFromEnergy); // CCD_AMOUNT / MICRO_CCD_PER_EURO_1 = 1000000 / (16626124143116419072/78228883861) = 1222326310328125/259783189736194048