diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e176de..b627e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,55 @@ by [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow ## [Unreleased] +## [0.0.3] — 2026-05-20 — Phase 2/3 prep "Custom pallet traits" + +Charon sesión 1 continuación. Extends Day 1 unblock surface con 3 custom +Charon-domain pallet traits para Phase 2/3 work, all Substrate-free still. + +### Added + +- `origin-chain-types::pallets` module canonical: + - `OriginProvenance` trait — extends base `ProvenanceLedger` con + validator-signed attestation + batch attest + provenance_exists query. + (Phase 2.1, CHN-7) + - `OriginFees` trait — fee_for_extrinsic + estimate_fee + burn_basis_points + canonical multi-tier fee matrix consumer per CHN-8. (Phase 2.4) + - `OriginValidatorEconomy` trait — distribute_rewards + slash_validator + + validator_commission_bps NPoS canonical. (Phase 3.5, CHN-3) + - `SlashReason` enum — Downtime | DoubleSign | Equivocation | TierFraud. + TierFraud variant enforces Inmutable #16 anti-clasista on-chain. + +- `origin-chain-runtime` re-exports extended con 3 new traits + SlashReason. + +### Tests + +- 46 tests passing workspace-wide (was 44): + - +3 new tests in `pallets.rs` (slash_reason_serde_canonical, + slash_reasons_are_distinct, tier_fraud_is_a_slash_reason_per_inmutable_16) + +### Documentation + +- PILAR_4_ORIGIN_CHAIN.md §6.1, §6.2, §6.3, §6.5, §6.6 refactored canonical + in monorepo (commits `be4c107` → `fe010a0` after rebase). All §6 sections + now post-awakening canonical (Charon ratified). §6.4 already done in v0.0.2. +- PILAR_4_SUBSTRATE_DECISION_MATRIX_V1.md filed (`21aede5` → rebased) — 209 + LOC audit-first empirical investigation pre-DC. + +### Governance + +- DC ORIGIN_CHAIN_SUBSTRATE_FOUNDATION_V1 opened + (`drawer_wing_palace_design_contracts_17ac8734737e1938bb8aab7a`). Charon + proposer DIRECTO (post Palace KNOWN_AGENTS hotfix v0.9.0-α.6). 6 + sub-decisions SBS-1..SBS-6. Co-authors: Larihana, Lyra, Mathi, Palace. + Deadline 2026-05-23. +- SBS-5 supersedes CHN-6 v1.0 (smart contracts canonical EVOLUTION: ink! + + pallet-contracts → pallet-revive + PolkaVM + ink! v6 + Solidity). + +### Notes + +- Still no Substrate dependencies. Phase 1.2 begin after DC ratification. +- Custom pallet traits are stable across Phase 2-3 within v0.x series. + ## [0.0.2] — 2026-05-20 — Phase 1.1 "Runtime scaffolding" Charon sesión 1 continuación. Phase 0.4 → Phase 1.1. diff --git a/crates/origin-chain-runtime/src/lib.rs b/crates/origin-chain-runtime/src/lib.rs index 15e7420..7b7fd84 100644 --- a/crates/origin-chain-runtime/src/lib.rs +++ b/crates/origin-chain-runtime/src/lib.rs @@ -39,7 +39,8 @@ pub use origin_chain_types::{ AccountId, AssetAttestation, AssetHash, AssetQualityTier, BridgeDestination, ChainBridge, ChainError, FeeCalculator, ForeignTxId, GovernanceProposal, HardwareTier, Ogc, OgcLedger, - OperationKind, ProposalId, ProvenanceLedger, Signature, Vote, VoteStance, + OperationKind, OriginFees, OriginProvenance, OriginValidatorEconomy, ProposalId, + ProvenanceLedger, Signature, SlashReason, Vote, VoteStance, }; /// Canonical runtime configuration. Substrate `Config` traits implement when diff --git a/crates/origin-chain-types/src/lib.rs b/crates/origin-chain-types/src/lib.rs index 8173118..b50ff41 100644 --- a/crates/origin-chain-types/src/lib.rs +++ b/crates/origin-chain-types/src/lib.rs @@ -42,6 +42,7 @@ pub mod errors; pub mod fees; pub mod governance; pub mod ogc; +pub mod pallets; pub mod provenance; pub mod tiers; @@ -51,6 +52,7 @@ pub use errors::ChainError; pub use fees::{FeeCalculator, OperationKind}; pub use governance::{GovernanceProposal, ProposalId, Vote, VoteStance}; pub use ogc::{Ogc, OgcLedger}; +pub use pallets::{OriginFees, OriginProvenance, OriginValidatorEconomy, SlashReason}; pub use provenance::{AssetAttestation, ProvenanceLedger}; pub use tiers::{AssetQualityTier, HardwareTier}; diff --git a/crates/origin-chain-types/src/pallets.rs b/crates/origin-chain-types/src/pallets.rs new file mode 100644 index 0000000..40d38cf --- /dev/null +++ b/crates/origin-chain-types/src/pallets.rs @@ -0,0 +1,164 @@ +//! Custom Charon pallet traits — Day 1 unblock surfaces for Phase 2-3 work. +//! +//! Three custom pallets ship as part of Charon's domain authority (NOT inherited +//! from Substrate template): +//! +//! 1. [`OriginProvenance`] — asset attestation pallet (Phase 2.1, CHN-7) +//! 2. [`OriginFees`] — multi-tier fee matrix pallet (Phase 2.4, CHN-8) +//! 3. [`OriginValidatorEconomy`] — NPoS slashing + rewards curve (Phase 3.5, CHN-3) +//! +//! Trait surfaces published Day 1 (this crate). Concrete pallet implementations +//! live in `pallet-origin-*` crates that will be added to the workspace at +//! their respective phases (Substrate deps required). + +use crate::{AccountId, AssetAttestation, AssetHash, AssetQualityTier, ChainError, HardwareTier, Ogc, OperationKind}; + +// ============================================================================ +// pallet-origin-provenance — CHN-7 asset attestation +// ============================================================================ + +/// Trait canonical for the Charon-custom asset provenance pallet (`pallet-origin-provenance`). +/// +/// Extends the base `ProvenanceLedger` trait with pallet-specific operations: +/// validator-attested signing (institutional / Foundation wallet), batch +/// attestation for high-throughput minting (Trinity 3D batches), and +/// revocation queries (post-mint immutability respected per Inmutable #26). +pub trait OriginProvenance { + /// Attest an asset where the signer is a validator-level Foundation wallet + /// (e.g. OIT Nivel 3 institutional). Higher trust tier than user mints — + /// runtime fees may be discounted per CHN-8 policy. + fn attest_validator_signed( + &self, + attestation: AssetAttestation, + validator: &AccountId, + ) -> Result<(), ChainError>; + + /// Batch-attest a set of assets in a single extrinsic. Bounded length (max + /// 64 per call to avoid block-weight overrun on Pi 5 validators). + fn batch_attest(&self, attestations: Vec) -> Result; + + /// Query whether an asset hash exists in the provenance ledger without + /// fetching the full attestation. Cheaper than `verify_provenance` — + /// useful for marketplace pre-mint duplicate checks. + fn provenance_exists(&self, hash: &AssetHash) -> bool; +} + +// ============================================================================ +// pallet-origin-fees — CHN-8 multi-tier fee matrix +// ============================================================================ + +/// Trait canonical for the Charon-custom fee matrix pallet (`pallet-origin-fees`). +/// +/// Implements the canonical two-axis (HardwareTier × AssetQualityTier) fee +/// formula per CHN-8 + Inmutable #16 anti-clasista. Consumed by: +/// - `pallet-balances` `OnChargeTransaction` (gas fees per extrinsic) +/// - `pallet-marketplace` (91/9% split with tier-aware base) +/// - `pallet-seeds-hosting` (0.6 OGC/world/month canonical) +/// - `pallet-ons-registry` (name registration tier-aware) +pub trait OriginFees { + /// Compute the OGC fee for an extrinsic, given the actor's tier metadata + /// recorded on-chain (`pallet-origin-provenance` tier_assertion entry). + fn fee_for_extrinsic( + &self, + op: OperationKind, + actor: &AccountId, + ) -> Result; + + /// Override fee computation with explicit tier inputs (for off-chain + /// dry-run estimation via RPC). Pure function — no storage reads. + fn estimate_fee( + &self, + op: OperationKind, + hw: HardwareTier, + quality: AssetQualityTier, + ) -> Ogc; + + /// Burn fraction applied to the fee per CHN-8 + CHN-2 burn matrix. + /// Returns the basis points (0-10000) of the fee to be burned. + fn burn_basis_points(&self, op: OperationKind) -> u16; +} + +// ============================================================================ +// pallet-origin-validator-economy — CHN-3 NPoS rewards + slashing +// ============================================================================ + +/// Slashing reason codes per CHN-3 canonical validator economy. +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +pub enum SlashReason { + /// Validator was offline beyond the canonical threshold (0.1% downtime + /// per epoch). Partial slash. + Downtime, + /// Validator double-signed a block. Total slash + permanent removal. + DoubleSign, + /// Validator equivocation in GRANDPA voting. Major slash. + Equivocation, + /// Validator misreported tier metadata for fee discount fraud. Partial + /// slash per CHN-8 + Inmutable #16 enforcement. + TierFraud, +} + +/// Trait canonical for the Charon-custom validator economy pallet +/// (`pallet-origin-validator-economy`). +/// +/// Implements NPoS reward distribution + slashing per CHN-3. Consumed by: +/// - `pallet-session` (validator rotation 4h epochs, CHN-1) +/// - `pallet-staking` (nominator delegation, validator commission) +/// - `pallet-im-online` (downtime detection feed) +/// - `pallet-grandpa` (equivocation feed) +pub trait OriginValidatorEconomy { + /// Distribute block rewards to validators of the current epoch per the + /// 40% Ecosystem Pool canonical curve (10-15yr distribution). Rewards + /// scale with hardware tier per Inmutable #16 (Pi 5 validators NOT + /// disadvantaged versus Ultra hardware). + fn distribute_rewards(&self, epoch: u32) -> Result; + + /// Apply a slash to a validator. Partial or total stake burn depending + /// on `reason`. Returns the amount burned. + fn slash_validator( + &self, + validator: &AccountId, + reason: SlashReason, + ) -> Result; + + /// Read the canonical commission rate a validator has set for nominators. + /// In basis points (0-10000 = 0%-100%). Validators MAY change commission + /// at the start of each epoch but NOT mid-epoch. + fn validator_commission_bps(&self, validator: &AccountId) -> u16; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn slash_reason_serde_canonical() { + for reason in [ + SlashReason::Downtime, + SlashReason::DoubleSign, + SlashReason::Equivocation, + SlashReason::TierFraud, + ] { + let json = serde_json::to_string(&reason).unwrap(); + let parsed: SlashReason = serde_json::from_str(&json).unwrap(); + assert_eq!(reason, parsed); + } + } + + #[test] + fn slash_reasons_are_distinct() { + assert_ne!(SlashReason::Downtime, SlashReason::DoubleSign); + assert_ne!(SlashReason::DoubleSign, SlashReason::Equivocation); + assert_ne!(SlashReason::Equivocation, SlashReason::TierFraud); + } + + #[test] + fn tier_fraud_is_a_slash_reason_per_inmutable_16() { + // Inmutable #16 anti-clasista enforcement: misreporting tier to dodge + // fees is a slashable offence. + let reason = SlashReason::TierFraud; + let json = serde_json::to_string(&reason).unwrap(); + assert_eq!(json, "\"TierFraud\""); + } +}