fix(security): audit fixes across 9 custom pallets

- pez-rewards: checked arithmetic in parliamentary reward distribution
- tiki: saturating_add in get_tiki_score fold, benchmarking cleanup
- ping: saturating_add on PingCount
- staking-score: saturating_mul on 4 duration multipliers
- pez-treasury: proper error on TreasuryStartBlock None, saturating_add on NextReleaseMonth, doc fix 70->75%
- messaging: InboxOverflow event on FIFO eviction
- token-wrapper: reorder wrap/unwrap operations, add pallet balance pre-check
- welati: u64 cast for turnout percentage overflow prevention
- presale: fix refund calculation to use net_in_treasury (98%) instead of impossible 99%, update tests
This commit is contained in:
2026-03-22 18:56:37 +03:00
parent fe49037cbe
commit 896f94ca97
13 changed files with 148 additions and 54 deletions
@@ -151,15 +151,16 @@ pub mod pezpallet {
)
.map_err(|_| Error::<T>::TransferFailed)?;
// Update total locked
// Mint wrapped tokens to user BEFORE updating TotalLocked
// If mint fails, the extrinsic reverts (including the transfer above)
T::Assets::mint_into(T::WrapperAssetId::get(), &who, amount)
.map_err(|_| Error::<T>::MintFailed)?;
// Update total locked only after both transfer and mint succeeded
TotalLocked::<T>::mutate(|total| {
*total = total.saturating_add(amount);
});
// Mint wrapped tokens to user
T::Assets::mint_into(T::WrapperAssetId::get(), &who, amount)
.map_err(|_| Error::<T>::MintFailed)?;
Self::deposit_event(Event::Wrapped { who, amount });
Ok(())
}
@@ -188,6 +189,10 @@ pub mod pezpallet {
let wrapped_balance = T::Assets::balance(T::WrapperAssetId::get(), &who);
ensure!(wrapped_balance >= amount, Error::<T>::InsufficientWrappedBalance);
// Verify pallet has sufficient backing before any state changes
let pallet_balance = T::Currency::free_balance(&Self::account_id());
ensure!(pallet_balance >= amount, Error::<T>::TransferFailed);
// Burn wrapped tokens from user
T::Assets::burn_from(
T::WrapperAssetId::get(),
@@ -199,12 +204,8 @@ pub mod pezpallet {
)
.map_err(|_| Error::<T>::BurnFailed)?;
// Update total locked
TotalLocked::<T>::mutate(|total| {
*total = total.saturating_sub(amount);
});
// Transfer native tokens back to user (unlock)
// If this fails, the extrinsic reverts (including the burn above)
T::Currency::transfer(
&Self::account_id(),
&who,
@@ -213,6 +214,11 @@ pub mod pezpallet {
)
.map_err(|_| Error::<T>::TransferFailed)?;
// Update total locked only after both burn and transfer succeeded
TotalLocked::<T>::mutate(|total| {
*total = total.saturating_sub(amount);
});
Self::deposit_event(Event::Unwrapped { who, amount });
Ok(())
}