diff --git a/smart-contracts/contracts-common/concordium-contracts-common/src/impls.rs b/smart-contracts/contracts-common/concordium-contracts-common/src/impls.rs index 5c2df4194..321f6a673 100644 --- a/smart-contracts/contracts-common/concordium-contracts-common/src/impls.rs +++ b/smart-contracts/contracts-common/concordium-contracts-common/src/impls.rs @@ -301,6 +301,46 @@ impl Deserial for ExchangeRate { } } +impl Serial for ExchangeRates { + fn serial(&self, out: &mut W) -> Result<(), W::Err> { + self.euro_per_energy.serial(out)?; + self.micro_ccd_per_euro.serial(out)?; + Ok(()) + } +} + +impl Deserial for ExchangeRates { + fn deserial(source: &mut R) -> ParseResult { + let bytes: [u8; 32] = source.read_array()?; + let chunks = unsafe { transmute::<[u8; 32], [[u8; 8]; 4]>(bytes) }; + + let euro_per_energy_numerator = u64::from_le_bytes(chunks[0]); + let euro_per_energy_denominator = u64::from_le_bytes(chunks[1]); + let micro_ccd_per_euro_numerator = u64::from_le_bytes(chunks[2]); + let micro_ccd_per_euro_denominator = u64::from_le_bytes(chunks[3]); + + if euro_per_energy_numerator == 0 + || euro_per_energy_denominator == 0 + || micro_ccd_per_euro_numerator == 0 + || micro_ccd_per_euro_denominator == 0 + { + return Err(ParseError::default()); + } + + let euro_per_energy = + ExchangeRate::new_unchecked(euro_per_energy_numerator, euro_per_energy_denominator); + let micro_ccd_per_euro = ExchangeRate::new_unchecked( + micro_ccd_per_euro_numerator, + micro_ccd_per_euro_denominator, + ); + + Ok(Self { + euro_per_energy, + micro_ccd_per_euro, + }) + } +} + impl Serial for ModuleReference { fn serial(&self, out: &mut W) -> Result<(), W::Err> { out.write_all(self.as_ref()) } } diff --git a/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs b/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs index fa9f4cb51..70b7a2c70 100644 --- a/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs +++ b/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs @@ -1439,6 +1439,37 @@ impl ExchangeRate { pub fn denominator(&self) -> u64 { self.denominator } } +/// The euro/NRG and microCCD/euro exchange rates. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ExchangeRates { + /// Euro per NRG exchange rate. + pub euro_per_energy: ExchangeRate, + /// Micro CCD per Euro exchange rate. + pub micro_ccd_per_euro: ExchangeRate, +} + +impl ExchangeRates { + /// Convert Euro cent to CCD using the current exchange rate. + /// This will round down to the nearest micro CCD. + pub fn convert_euro_cent_to_amount(&self, euro_cent: u64) -> Amount { + let numerator: u128 = self.micro_ccd_per_euro.numerator().into(); + let denominator: u128 = self.micro_ccd_per_euro.denominator().into(); + let euro_cent: u128 = euro_cent.into(); + let result = numerator * euro_cent / (denominator * 100); + Amount::from_micro_ccd(result as u64) + } + + /// Convert CCD to Euro cent using the current exchange rate. + /// This will round down to the nearest Euro cent. + pub fn convert_amount_to_euro_cent(&self, amount: Amount) -> u64 { + let numerator: u128 = self.micro_ccd_per_euro.numerator().into(); + let denominator: u128 = self.micro_ccd_per_euro.denominator().into(); + let micro_ccd: u128 = amount.micro_ccd().into(); + let result = micro_ccd * 100 * denominator / numerator; + result as u64 + } +} + /// Chain metadata accessible to both receive and init methods. #[cfg_attr( feature = "derive-serde",