diff --git a/crates/origin-chain-emission/src/lib.rs b/crates/origin-chain-emission/src/lib.rs index 2064b65..0ebc2bd 100644 --- a/crates/origin-chain-emission/src/lib.rs +++ b/crates/origin-chain-emission/src/lib.rs @@ -180,9 +180,23 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { + /// Guard de integridad (audit ultra 2026-07-02): las shares autor + + /// treasury JAMÁS pueden exceder 100% — el residual es el subsidy pool + /// (`subsidy = reward − author − treasury`). Si un futuro cambio de + /// config las hiciera sumar > 10_000 bps, el `saturating_sub` daría + /// subsidy = 0 SILENCIOSAMENTE. Esto lo convierte en un fallo ruidoso + /// en el build/integrity-check del runtime. + fn integrity_test() { + assert!( + T::AuthorShareBps::get().saturating_add(T::TreasuryShareBps::get()) <= 10_000, + "emisión: AuthorShareBps + TreasuryShareBps no pueden exceder 100% \ + (el residual es el subsidy pool #16)" + ); + } + /// Cada bloque: identifica al autor Aura (desde los pre-runtime digests), - /// mintea el BlockReward y lo reparte. Si no hay autor (e.g. bloque de - /// inherentes sin pre-digest), no mintea. + /// libera el BlockReward del pool Ecosystem y lo reparte. Si no hay autor + /// (e.g. bloque de inherentes sin pre-digest), no libera. fn on_initialize(_n: BlockNumberFor) -> Weight { // Kill-switch (governance): si la emisión está pausada, no libera nada. // Lee 1 storage value; default `false` ⇒ activa (cero regresión). @@ -496,6 +510,14 @@ mod tests { }); } + #[test] + fn integrity_test_shares_no_exceden_100pct() { + new_test_ext().execute_with(|| { + // Mock: 7000 + 2000 = 9000 ≤ 10000 ⇒ pasa (el residual 1000 = subsidy). + >::integrity_test(); + }); + } + #[test] fn depletion_event_se_anuncia_una_sola_vez() { new_test_ext_with_pool(500).execute_with(|| {