feat(economía): techo duro 1B + fees con dientes (David Level A 2026-07-03, RV 6→7)
Dos decisiones económicas ratificadas por David, verificadas en fuente:
1. TECHO DURO 1B (Opción A) — la emisión TRANSFIERE del pool Ecosystem finito
(og/ecosy, 400M pre-asignado en génesis), JAMÁS mint_into. La aserción de
compilación de 1.000M deja de ser promesa de génesis y se vuelve ley que la
producción de bloques obedece: el total issuance nunca crece, el pool se
agota en ~7.6 años (10 OGC/bloque), después economía circular pura. Cuando el
pool no cubre el reward completo, libera el remanente y emite
EcosystemPoolDepleted una vez. Evento renombrado BlockRewardMinted →
BlockRewardReleased (honestidad: es redistribución, no acuñación).
- origin-chain-emission: Currency.transfer (Expendable) desde ecosystem_account;
+EcosystemPalletId config, +DepletionAnnounced storage one-shot, +2 tests
(hard_cap_pool_se_agota_y_para, depletion_event_se_anuncia_una_sola_vez).
- runtime: EmissionEcosystemPalletId (og/ecosy) wired; génesis asigna el 40%
a la cuenta PalletId determinista (sin llave humana), no al placeholder ECO!.
2. FEES CON DIENTES — WeightToFee/LengthToFee de IdentityFee (polvo ~10^-10 OGC,
#16 = adorno) a ConstantMultiplier calibrado: un transfer simple ≈ 1 MILLI_OGC
(0.001 OGC). Consecuencias: el descuento Pi5 (0.1×) = ahorro real (0.0001 OGC);
la quema del 100% de gas es deflación medible desde el testnet; el spam cuesta
OGC real. Factor 7e6 (weight) + 1e11 (length). Test de regresión
weight_to_fee_transfer_tiene_dientes_no_polvo blinda contra revertir a polvo.
Calibrado a pesos placeholder — re-tunear con benchmarks reales (leftover FIX-2).
RUNTIME_VERSION 6→7. Workspace 275 tests verde, 0 fallos. TRANSACTION_VERSION intacto.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b8863fd47
commit
1fdc47e859
4 files changed
+282
-65
No files matched your search
@@ -167,6 +167,23 @@ parameter_types! {
|
||||
/// benchmarking real (leftover FIX-2).
|
||||
pub FeeMultiplierOne: pallet_transaction_payment::Multiplier =
|
||||
pallet_transaction_payment::Multiplier::from_u32(1);
|
||||
|
||||
/// Factor WeightToFee (base units OGC por unidad de ref_time). Calibrado
|
||||
/// (David 2026-07-03) para que OCAFB-5 tenga DIENTES: con IdentityFee el fee
|
||||
/// base de un transfer era ~2×10^-10 OGC (polvo cósmico) y el #16 anti-
|
||||
/// clasista era un adorno. Con este factor, un transfer simple (ExtrinsicBase
|
||||
/// 108.157M + transfer_keep_alive ~39M ≈ 1.47×10^8 ref_time) cuesta:
|
||||
/// 1.47×10^8 × 7×10^6 ≈ 1.03×10^15 base units ≈ **1 MILLI_OGC (0.001 OGC)**.
|
||||
/// Consecuencias: el descuento Pi5 (0.1×) = ahorro real (0.0001 OGC); la
|
||||
/// quema del 100% de gas es deflación medible desde el testnet; el spam
|
||||
/// cuesta OGC real. Calibrado a pesos placeholder — re-tunear con benchmarks
|
||||
/// reales (leftover FIX-2). `ConstantMultiplier` usa solo ref_time.
|
||||
pub const WeightFeeFactor: Balance = 7_000_000;
|
||||
|
||||
/// Factor LengthToFee: 10^11 base units por byte ⇒ 1 KiB ≈ 0.0001 OGC. Da
|
||||
/// costo real (anti-bloat) a extrinsics grandes (código de contrato, remarks)
|
||||
/// sin dominar el fee de un tx normal (150 bytes ≈ 0.000015 OGC).
|
||||
pub const LengthFeeFactor: Balance = 100_000_000_000;
|
||||
}
|
||||
|
||||
/// FIX-6 Stage 2a: clasificador call→ChainAction del fee unificado (taxonomía
|
||||
@@ -223,8 +240,11 @@ impl pallet_transaction_payment::Config for Runtime {
|
||||
type OnChargeTransaction =
|
||||
origin_chain_fees::OriginFeeAdapter<crate::Balances, (), OriginCallClassifier>;
|
||||
type OperationalFeeMultiplier = OperationalFeeMultiplier;
|
||||
type WeightToFee = frame_support::weights::IdentityFee<Balance>;
|
||||
type LengthToFee = frame_support::weights::IdentityFee<Balance>;
|
||||
/// Calibrado (David 2026-07-03): un transfer simple ≈ 1 MILLI_OGC. NUNCA
|
||||
/// `IdentityFee` — con 18 decimales el fee base era polvo (~10^-10 OGC) y
|
||||
/// anulaba el #16. Ver `WeightFeeFactor`.
|
||||
type WeightToFee = frame_support::weights::ConstantMultiplier<Balance, WeightFeeFactor>;
|
||||
type LengthToFee = frame_support::weights::ConstantMultiplier<Balance, LengthFeeFactor>;
|
||||
/// NUNCA `()` aquí: colapsa `NextFeeMultiplier` a 0 (ver `FeeMultiplierOne`).
|
||||
type FeeMultiplierUpdate = pallet_transaction_payment::ConstFeeMultiplier<FeeMultiplierOne>;
|
||||
type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
|
||||
@@ -481,22 +501,31 @@ impl origin_chain_governance::Config for Runtime {
|
||||
// origin_chain_emission::Config — FIX-6 Stage 1 (audit V2-CA2)
|
||||
// ============================================================
|
||||
//
|
||||
// En cada bloque mintea EmissionBlockReward y lo reparte: 70% al autor (el
|
||||
// validador Aura), 20% al treasury (og/gvtry, la MISMA cuenta de governance),
|
||||
// 10% al subsidy pool (og/subsy, proof-of-equity que financia el subsidio de
|
||||
// hardware #16 — ortogonal a la suscripción, David 2026-06-10). Cierra "los
|
||||
// validadores ganan 0 OGC". FindAuthor = el mapeo Aura→validador de session.
|
||||
// En cada bloque LIBERA EmissionBlockReward del pool Ecosystem (og/ecosy, 400M)
|
||||
// y lo reparte: 70% al autor (el validador Aura), 20% al treasury (og/gvtry, la
|
||||
// MISMA cuenta de governance), 10% al subsidy pool (og/subsy, proof-of-equity
|
||||
// que financia el subsidio de hardware #16 — ortogonal a la suscripción, David
|
||||
// 2026-06-10). Cierra "los validadores ganan 0 OGC". FindAuthor = el mapeo
|
||||
// Aura→validador de session.
|
||||
//
|
||||
// BlockReward 10 OGC × ~5.256M bloques/año ≈ 52.6M OGC/año ≈ 5.26% inflación
|
||||
// sobre el genesis de 1B (materializa la emisión del 40% Ecosystem BM V2).
|
||||
// TECHO DURO 1B (David 2026-07-03, Opción A): transfer del pool finito, NUNCA
|
||||
// mint. BlockReward 10 OGC × ~5.256M bloques/año ≈ 52.6M OGC/año ⇒ el pool de
|
||||
// 400M se agota en ~7.6 años; después, economía circular. El total issuance
|
||||
// JAMÁS crece — la aserción de compilación de 1B se cumple a rajatabla.
|
||||
// Stage 2 introduce pallet_staking NPoS sobre este substrate.
|
||||
parameter_types! {
|
||||
/// Recompensa por bloque: 10 OGC (~5% inflación anual).
|
||||
/// Recompensa por bloque: 10 OGC. NO es inflación — es el ritmo de
|
||||
/// LIBERACIÓN del pool Ecosystem finito (400M): 10 × ~5.256M bloques/año ≈
|
||||
/// 52.6M/año ⇒ el pool se agota en ~7.6 años (techo duro 1B, David 2026-07-03).
|
||||
pub const EmissionBlockReward: Balance = 10 * OGC;
|
||||
/// 70% al autor (validador Aura).
|
||||
pub const EmissionAuthorShareBps: u16 = 7_000;
|
||||
/// 20% al treasury (el residual 10% va al subsidy pool).
|
||||
pub const EmissionTreasuryShareBps: u16 = 2_000;
|
||||
/// PalletId del pool Ecosystem (40% = 400M en génesis) — la FUENTE finita de
|
||||
/// las recompensas. La emisión transfiere de aquí, jamás mintea (techo duro).
|
||||
pub const EmissionEcosystemPalletId: frame_support::PalletId =
|
||||
frame_support::PalletId(*b"og/ecosy");
|
||||
/// PalletId del subsidy pool (proof-of-equity, #16 anti-clasista).
|
||||
pub const EmissionSubsidyPalletId: frame_support::PalletId =
|
||||
frame_support::PalletId(*b"og/subsy");
|
||||
@@ -510,6 +539,8 @@ impl origin_chain_emission::Config for Runtime {
|
||||
type BlockReward = EmissionBlockReward;
|
||||
type AuthorShareBps = EmissionAuthorShareBps;
|
||||
type TreasuryShareBps = EmissionTreasuryShareBps;
|
||||
// La FUENTE finita: el pool Ecosystem (og/ecosy) = 400M pre-asignado en génesis.
|
||||
type EcosystemPalletId = EmissionEcosystemPalletId;
|
||||
// Reusa el MISMO vault de governance (og/gvtry) para el treasury.
|
||||
type TreasuryPalletId = GovernanceTreasuryPalletId;
|
||||
type SubsidyPalletId = EmissionSubsidyPalletId;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#![cfg(feature = "std")]
|
||||
|
||||
use crate::{
|
||||
configs::{AuraId, GovernanceTreasuryPalletId, GrandpaId},
|
||||
configs::{AuraId, EmissionEcosystemPalletId, GovernanceTreasuryPalletId, GrandpaId},
|
||||
opaque::SessionKeys,
|
||||
Balance, ChainAccountId, Ogc, RuntimeGenesisConfig,
|
||||
};
|
||||
@@ -360,7 +360,12 @@ pub fn mainnet_genesis_config_genesis() -> RuntimeGenesisConfig {
|
||||
account_from_sr25519(bytes)
|
||||
};
|
||||
|
||||
let ecosystem_pool = make_placeholder(b"ECO!"); // Ecosystem/Rewards Pool canonical
|
||||
// El 40% Ecosystem (400M) se asigna a la cuenta PalletId `og/ecosy` — la
|
||||
// MISMA de la que `pallet-origin-emission` LIBERA las recompensas de bloque
|
||||
// (transfer, techo duro 1B; David 2026-07-03). No es un placeholder key-
|
||||
// controlado: es la cuenta determinista del pool, sin llave humana.
|
||||
let ecosystem_pool: ChainAccountId =
|
||||
EmissionEcosystemPalletId::get().into_account_truncating();
|
||||
let foundation_treasury = make_placeholder(b"FNDT"); // Foundation multisig = sudo_key interim
|
||||
let public_sale = make_placeholder(b"SALE"); // Public Sale canonical
|
||||
let founding_team = make_placeholder(b"TEAM"); // Founding Team canonical (4yr vesting)
|
||||
|
||||
@@ -243,7 +243,15 @@ pub const IMPL_NAME: &str = "origin-chain-charon";
|
||||
/// `TotalEmitted` + evento registran SOLO lo realmente acuñado (resultados de
|
||||
/// `mint_into` ya no se descartan). Cambia comportamiento ⇒ spec bump;
|
||||
/// TRANSACTION_VERSION intacto.
|
||||
pub const RUNTIME_VERSION: u32 = 6;
|
||||
/// v7: economía Level A (David 2026-07-03, 2 decisiones) — (a) **TECHO DURO 1B**:
|
||||
/// la emisión TRANSFIERE del pool Ecosystem finito (og/ecosy, 400M) en vez de
|
||||
/// `mint_into`; el total issuance jamás crece, el pool se agota en ~7.6 años,
|
||||
/// después economía circular (evento `BlockRewardReleased` + `EcosystemPoolDepleted`
|
||||
/// one-shot). (b) **fees con dientes**: `WeightToFee`/`LengthToFee` de `IdentityFee`
|
||||
/// (polvo ~10^-10 OGC) a `ConstantMultiplier` calibrado — un transfer ≈ 1 MILLI_OGC,
|
||||
/// el #16 Pi5 0.1× = ahorro real, quema deflacionaria medible. Comportamiento ⇒
|
||||
/// spec bump; TRANSACTION_VERSION intacto.
|
||||
pub const RUNTIME_VERSION: u32 = 7;
|
||||
|
||||
/// Canonical authoring version per Substrate semver canonical.
|
||||
pub const AUTHORING_VERSION: u32 = 1;
|
||||
@@ -835,12 +843,12 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn runtime_version_v6_ultra_audit_fixes() {
|
||||
// v6 = 3 fixes del audit ultra 2026-07-02: ConstFeeMultiplier (el `()`
|
||||
// colapsaba NextFeeMultiplier a 0), NativeToEthRatio=1 (OGC 18 dec),
|
||||
// y emisión con contabilidad honesta de mint_into. Cambios de
|
||||
// comportamiento, no de formato de extrinsic ⇒ TRANSACTION_VERSION intacto.
|
||||
assert_eq!(RUNTIME_VERSION, 6);
|
||||
fn runtime_version_v7_hard_cap_and_fee_teeth() {
|
||||
// v7 = economía Level A (David 2026-07-03): techo duro 1B (emisión =
|
||||
// transfer del pool Ecosystem, no mint) + fees con dientes (ConstantMultiplier
|
||||
// calibrado, transfer ≈ 1 MILLI_OGC). Cambios de comportamiento, no de
|
||||
// formato de extrinsic ⇒ TRANSACTION_VERSION intacto.
|
||||
assert_eq!(RUNTIME_VERSION, 7);
|
||||
assert_eq!(TRANSACTION_VERSION, 1);
|
||||
}
|
||||
|
||||
@@ -952,6 +960,25 @@ mod tests {
|
||||
assert!(!next.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weight_to_fee_transfer_tiene_dientes_no_polvo() {
|
||||
// Calibración David 2026-07-03 (v7): un transfer simple debe costar ~1
|
||||
// MILLI_OGC, NO el polvo ~10^-10 OGC de IdentityFee (que anulaba el #16).
|
||||
// Guard de regresión: si alguien revierte a IdentityFee, el fee cae a
|
||||
// ~1.5×10^8 base units (muy por debajo de MILLI_OGC/2) y esto rompe.
|
||||
use frame_support::weights::{Weight, WeightToFee as _};
|
||||
// transfer ≈ ExtrinsicBaseWeight (108.157M) + transfer_keep_alive (~39M).
|
||||
let transfer_weight = Weight::from_parts(108_157_000 + 39_051_000, 0);
|
||||
let fee = <<Runtime as pallet_transaction_payment::Config>::WeightToFee>::weight_to_fee(
|
||||
&transfer_weight,
|
||||
);
|
||||
assert!(
|
||||
fee >= MILLI_OGC / 2 && fee <= MILLI_OGC * 3,
|
||||
"fee de transfer = {fee} base units; esperado ~1 MILLI_OGC ({MILLI_OGC}), \
|
||||
ni polvo ni exorbitante"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn revive_deposit_per_byte_canonical_milli_ogc() {
|
||||
// Asset Hub pattern adapted OGC tokenomics — 1 MILLI_OGC per byte canonical.
|
||||
|
||||
Reference in new issue
Block a user