Contractless/src/orphans/undo_transactions/undo_burn.rs

119 lines
4.7 KiB
Rust

use crate::blocks::burn::BurnTransaction;
use crate::common::network_paths_and_settings::block_extension_and_paths;
use crate::common::nft_assets::nft_asset_name;
use crate::common::nft_assets::NFT_UNIT;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::token_provenance::remove_token_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_burn_transaction(transaction: BurnTransaction, mining_receiver: &str, db: &Db) {
// Reverse the burn fee and burned-asset balance movement before
// restoring the live token or NFT state back into the active chain.
let operand_subtraction = "subtraction";
let operand_addition = "addition";
let (
_network_name,
_padded_base_coin,
type_str,
_torrentpath,
_wallet_path,
_blockpath,
_db_path,
_balance_path,
_log_path,
) = block_extension_and_paths();
let burned_asset = nft_asset_name(
&transaction.unsigned_burn.coin,
transaction.unsigned_burn.nft_series,
);
// Remove the miner fee, refund the burner fee, and return the burned asset
// to the burner balance.
let _ = balance_sheet_operation_with_db(
db,
mining_receiver,
transaction.unsigned_burn.txfee,
&type_str,
operand_subtraction,
);
let _ = balance_sheet_operation_with_db(
db,
&transaction.unsigned_burn.address,
transaction.unsigned_burn.txfee,
&type_str,
operand_addition,
);
let _ = balance_sheet_operation_with_db(
db,
&transaction.unsigned_burn.address,
transaction.unsigned_burn.value,
&burned_asset,
operand_addition,
);
let hash_binary = decode(&transaction.unsigned_burn.hash().await).unwrap();
let _ = remove_wallet_transaction_index(
db,
&[&transaction.unsigned_burn.address, mining_receiver],
&hash_binary,
);
// Delete the txid lookup inserted when the burn was saved.
let txid_tree = db.open_tree("txid").unwrap();
txid_tree.remove(hash_binary.clone()).unwrap();
// Restore NFT rows directly, or add the burned amount back into the
// fungible token supply if this burn targeted a token asset.
let nft_tree = db.open_tree("nfts").unwrap();
let nft_ownership_tree = db.open_tree("nft_ownership").unwrap();
if nft_ownership_tree
.contains_key(burned_asset.as_bytes())
.unwrap_or(false)
{
// Restore the exact burned ownership amount. The immutable ownership
// tree restores the live registry correctly after a final-unit burn.
let _ = remove_nft_history_entry(db, &burned_asset, &hash_binary);
let ownership_type = nft_ownership_tree
.get(burned_asset.as_bytes())
.unwrap()
.expect("NFT/RWA ownership record disappeared during burn rollback");
let nft_supply_tree = db.open_tree("nft_supply").unwrap();
let current_supply = nft_supply_tree
.get(burned_asset.as_bytes())
.unwrap()
.map(|bytes| {
let mut supply_bytes = [0u8; 8];
supply_bytes.copy_from_slice(bytes.as_ref());
u64::from_le_bytes(supply_bytes)
})
.unwrap_or(0);
let restored_supply = current_supply
.checked_add(transaction.unsigned_burn.value)
.filter(|supply| *supply <= NFT_UNIT)
.expect("NFT/RWA supply overflow during burn rollback");
let _ = nft_supply_tree.insert(burned_asset.as_bytes(), &restored_supply.to_le_bytes());
let _ = nft_tree.insert(burned_asset.as_bytes(), ownership_type);
} else {
// Token burns reduce supply; rollback adds the burned amount back.
let _ = remove_token_history_entry(db, &transaction.unsigned_burn.coin, &hash_binary);
let token_tree = db.open_tree("tokens").unwrap();
let current_supply = token_tree
.get(transaction.unsigned_burn.coin.as_bytes())
.unwrap()
.map(|bytes| {
let mut supply_bytes = [0u8; 8];
supply_bytes.copy_from_slice(bytes.as_ref());
u64::from_le_bytes(supply_bytes)
})
.unwrap_or(0);
let restored_supply = current_supply.saturating_add(transaction.unsigned_burn.value);
let _ = token_tree.insert(
transaction.unsigned_burn.coin.as_bytes(),
&restored_supply.to_le_bytes(),
);
}
}