use bee_block::payload::milestone::{MilestoneIndex, ReceiptMilestoneOption};
use crate::{error::Error, TreasuryOutput};
#[derive(Clone, Debug, Eq, PartialEq, packable::Packable)]
pub struct Receipt {
inner: ReceiptMilestoneOption,
included_in: MilestoneIndex,
}
impl Receipt {
pub fn new(inner: ReceiptMilestoneOption, included_in: MilestoneIndex) -> Self {
Self { inner, included_in }
}
pub fn inner(&self) -> &ReceiptMilestoneOption {
&self.inner
}
pub fn included_in(&self) -> &MilestoneIndex {
&self.included_in
}
pub fn validate(&self, consumed_treasury_output: &TreasuryOutput, token_supply: u64) -> Result<(), Error> {
let mut migrated_amount: u64 = 0;
let transaction = self.inner().transaction();
for funds in self.inner().funds() {
migrated_amount = migrated_amount
.checked_add(funds.amount())
.ok_or_else(|| Error::MigratedFundsAmountOverflow(migrated_amount as u128 + funds.amount() as u128))?;
}
if migrated_amount > token_supply {
return Err(Error::InvalidMigratedFundsAmount(migrated_amount));
}
let input = transaction.input();
if input.milestone_id() != consumed_treasury_output.milestone_id() {
return Err(Error::ConsumedTreasuryOutputMismatch(
*input.milestone_id(),
*consumed_treasury_output.milestone_id(),
));
}
let created_treasury_output = transaction.output();
let created_amount = consumed_treasury_output
.inner()
.amount()
.checked_sub(migrated_amount)
.ok_or_else(|| {
Error::MigratedFundsAmountOverflow(
(consumed_treasury_output.inner().amount() as i128 - migrated_amount as i128) as u128,
)
})?;
if created_amount != created_treasury_output.amount() {
return Err(Error::TreasuryAmountMismatch(
created_amount,
created_treasury_output.amount(),
));
}
Ok(())
}
}