feat(fees): FIX-6 Stage 2a — fee unificado (cierra V2-CA3)
Pone la fórmula OCAFB-5 en el fee-path VIVO: OriginFeeAdapter (OnChargeTransaction custom) reemplaza al FungibleAdapter tier-blind. El firmante paga su fracción según (HardwareTier × ChainAction × SubscriptionTier, tiers leídos ON-CHAIN de TierProfiles — jamás caller-supplied), y el subsidy pool og/subsy (alimentado por la emisión Stage 1) cubre la fracción subsidiada. Inmutable #16 en cada transacción. OU=() = burn 100% gas fees (matriz CHN-2). unified_fee (u128, outcome tipado FeeOutcome — sin el sentinel u64::MAX in-band): user = fórmula vendor Mathi byte-fiel (test de paridad grid contra ce4fafb); pool = net × subsidy_bp/1e4 sobre el COSTO BASE (anti-regresivo, sub_mult ORTOGONAL: un Ultra NO drena el pool más que un Free — el premium lo paga el usuario, no el commons). Hallazgos de la verificación adversarial (workflow ultracode, 4 lentes) cerrados de raíz: - HIGH: clasificador cubre eth_instantiate_with_code (call_index 10) — evadía el entitlement-gate DeployContract vía fallback Write. - MEDIUM ledger envenenable: removido el dispatchable legacy compute_fee_for_action (tiers caller-supplied, escribía AccountFees sin cobrar). AccountFees ahora escrito SOLO por el fee-path vivo (note_settlement). Eventos que nunca se emitían eliminados; el preview read-only vive en query_fee / FeesApi. - MEDIUM drenaje del pool por sub_mult: pool sobre net, no sobre el precio premium (Opción B anti-regresiva). - Dev UX: GenesisConfig siembra perfiles iniciales; dev/local arrancan Ultra (los Slices 3.x de contracts no se bloquean por Free+DeployContract); mainnet vacío (Default conservador hasta attestation). Decisión de diseño (autoridad Pilar 4): replay de attestation = RECHAZO explícito, no dedup silencioso (notificado a Ergon para el reference impl). Orden OCAFB-5 subsidy-antes-de-entitlement preservado byte-fiel + notificado a Mathi para el ratify 2026-06-21. set_tier_profile Root-only interim (sunset a attestation-driven vía Mathi PerceptionAdapter + DID binding FIX-3/FIX-4). spec_version 1→2 (formato de extrinsic intacto, TRANSACTION_VERSION=1). Tests: 49 crate fees (paridad grid + lobo blanco ortogonalidad + refund + pool seco + tip passthrough + entitlement blocked) + 21 suites workspace verde. Toolchain cargo +1.88. Nota WASM: el build local del runtime WASM falla en la post-validación del substrate-wasm-builder con UnknownOpcode(252) — límite del toolchain (Rust 1.88 emite opcodes 0xFC que el parser del builder de stable2509 no deserializa). Reproducido idéntico en el HEAD intacto (v0.0.57): es ambiental, no de este cambio. El node real + WASM artifact siguen VPS-gated (toolchain alineado / wasm32v1-none cuando el wasm-builder lo soporte). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e6a803b54f
commit
3364994cce
10 files changed
+1435
-417
No files matched your search
@@ -159,13 +159,59 @@ parameter_types! {
|
||||
pub const OperationalFeeMultiplier: u8 = 5;
|
||||
}
|
||||
|
||||
/// FIX-6 Stage 2a: clasificador call→ChainAction del fee unificado (taxonomía
|
||||
/// OCAFB-2). Vive aquí porque el runtime es el único sitio donde `RuntimeCall`
|
||||
/// es concreto. Fallback conservador: `Write` (fee estándar — un wildcard
|
||||
/// jamás regala subsidio; mismo principio que la alerta TLB de Ergon).
|
||||
pub struct OriginCallClassifier;
|
||||
|
||||
impl origin_chain_fees::ClassifyChainAction<crate::RuntimeCall> for OriginCallClassifier {
|
||||
fn classify(call: &crate::RuntimeCall) -> origin_chain_fees::ChainAction {
|
||||
use origin_chain_fees::ChainAction;
|
||||
match call {
|
||||
crate::RuntimeCall::Balances(
|
||||
pallet_balances::Call::transfer_allow_death { .. }
|
||||
| pallet_balances::Call::transfer_keep_alive { .. }
|
||||
| pallet_balances::Call::transfer_all { .. },
|
||||
) => ChainAction::Transfer,
|
||||
crate::RuntimeCall::Revive(
|
||||
pallet_revive::Call::instantiate { .. }
|
||||
| pallet_revive::Call::instantiate_with_code { .. }
|
||||
// call_index 10: el deploy vía la capa EVM (Code::Upload). Sin
|
||||
// este arm caería en el fallback Write y evadiría el
|
||||
// entitlement-gate DeployContract (HIGH del audit Stage 2a).
|
||||
| pallet_revive::Call::eth_instantiate_with_code { .. },
|
||||
) => ChainAction::DeployContract,
|
||||
crate::RuntimeCall::Revive(
|
||||
pallet_revive::Call::call { .. }
|
||||
| pallet_revive::Call::eth_call { .. }
|
||||
// eth_transact: envoltorio EVM genérico (puede ser call/deploy/
|
||||
// transfer). Lo tratamos como ejecución de contrato — su
|
||||
// entitlement (Free=false) y subsidio coinciden con CallContract;
|
||||
// refinar cuando la capa EVM se cablee plenamente.
|
||||
| pallet_revive::Call::eth_transact { .. },
|
||||
) => ChainAction::CallContract,
|
||||
crate::RuntimeCall::Revive(pallet_revive::Call::upload_code { .. }) => {
|
||||
ChainAction::UploadContractCode
|
||||
}
|
||||
_ => ChainAction::Write,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_transaction_payment::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
/// On-charge transaction canonical: usa `pallet_transaction_payment` default
|
||||
/// charge mechanism. Phase 2.4 lo refactor canonical para integrar
|
||||
/// `OriginFees` trait (CHN-8 multi-tier fee matrix).
|
||||
/// FIX-6 Stage 2a (cierra V2-CA3): `OriginFeeAdapter` reemplaza al
|
||||
/// `FungibleAdapter` default — la fórmula OCAFB-5 entra al fee-path VIVO:
|
||||
/// el firmante paga su fracción según (HardwareTier × ChainAction ×
|
||||
/// SubscriptionTier, tiers leídos ON-CHAIN de `TierProfiles`, jamás
|
||||
/// caller-supplied), y el subsidy pool `og/subsy` (alimentado por la
|
||||
/// emisión Index 13) cubre la fracción subsidiada — Inmutable #16 en cada
|
||||
/// transacción. `OU = ()` deliberado: burn matrix CHN-2 ratificada = gas
|
||||
/// fees 100% burn (el burn total = fee constitucional completo, deflación
|
||||
/// que contrapesa la emisión Stage 1).
|
||||
type OnChargeTransaction =
|
||||
pallet_transaction_payment::FungibleAdapter<crate::Balances, ()>;
|
||||
origin_chain_fees::OriginFeeAdapter<crate::Balances, (), OriginCallClassifier>;
|
||||
type OperationalFeeMultiplier = OperationalFeeMultiplier;
|
||||
type WeightToFee = frame_support::weights::IdentityFee<Balance>;
|
||||
type LengthToFee = frame_support::weights::IdentityFee<Balance>;
|
||||
@@ -368,6 +414,10 @@ impl origin_chain_provenance::Config for Runtime {
|
||||
|
||||
impl origin_chain_fees::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
/// FIX-6 Stage 2a: la MISMA constante que alimenta la emisión (Index 13)
|
||||
/// — pool-alimentación y pool-consumo apuntan a la misma cuenta og/subsy
|
||||
/// (jamás re-declarar el literal: un typo divergiría las cuentas).
|
||||
type SubsidyPalletId = EmissionSubsidyPalletId;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
||||
Reference in new issue
Block a user