feat(fees): v0.0.22 — compute_fee_for_action impl complete + mock runtime integration tests E2E (10 scenarios)

Phase 2.4 FEES pallet REAL IMPL canonical. Dispatchable compute_fee_for_action
wire-up vendor compute_fee() pure fn call + AccountFees<StorageMap> saturating
arithmetic + event emission. Mock runtime + 10 integration tests E2E pattern
v0.0.18 mirror (Phase 2.1 PROVENANCE).

## Real impl canonical 5-step OCAFB-5

1. ensure_signed canonical
2. Vendor compute_fee(base, hw, sub, action) pure fn call
3. Handle entitlement blocked (fee==u64::MAX → Err(EntitlementLocked))
4. AccountFees<StorageMap> saturating update canonical
5. Emit FeeCharged event canonical

Pure helper Pallet::<T>::query_fee() para Runtime API v0.0.23 consumer.

## Consumer pattern canonical

Mathi OitFeeSchedule consumed CLIENT-SIDE — tx submitter queries Mathi per-user
→ assembles tx con (hw, sub) baked → submits. Pattern análogo Phase 2.1
attest_asset (ValidationAttestation pre-assembled client-side).

## 10 integration tests E2E

- scenario_1: Pi5 Write subsidy 90% → fee=1000 (Inmutable #16)
- scenario_2: Ultra Write Pro multiplier → fee=1500
- scenario_3: Read always free → fee=0 (Inmutable #37)
- scenario_4: Free Compute blocked → Err(EntitlementLocked)
- scenario_5: Pro Compute unlocked → fee=112
- scenario_6: Ultra Compute Ultra premium → fee=2000 (Inmutable #18)
- scenario_7: Storage accumulates Write×3 → total_paid=3375, count=3
- scenario_8: ChainAction ordinal stable wire (Read=0..Transfer=3)
- scenario_9: Inmutable #16 lobo blanco — Pi5 fee 1000 < Ultra fee 20000
- scenario_10: 5-step OCAFB-5 walkthrough explicit Pre/Post assertions

## FRAME canonical pattern

Events NOT emitted on Err path (FRAME revierte events on dispatch error).
EntitlementBlocked event variant retained para Phase 2.5 future
with_storage_layer pattern. Caller infers from Err return.

## Files canonical

- EDIT: crates/origin-chain-fees/src/lib.rs (real dispatchable impl + query_fee helper)
- NEW: crates/origin-chain-fees/src/mock.rs (80 LOC mock runtime pattern v0.0.18)
- NEW: crates/origin-chain-fees/src/tests_integration.rs (290 LOC, 10 tests)
- EDIT: crates/origin-chain-types/src/tiers.rs (FRAME derives Encode/Decode/TypeInfo/MaxEncodedLen para HardwareTier + SubscriptionTier + AssetQualityTier)
- EDIT: CHANGELOG.md (v0.0.22 entry comprehensive)

## Verification

- cargo test -p origin-chain-fees — 32 tests verde, 0 failures
- cargo test --workspace — 137 tests verde workspace, 0 failures
- Zero compile errors workspace-wide

🛠️ Phase 2.4 real impl canonical. Runtime API v0.0.23 next ship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
davidherranandClaude Opus 4.7 committed 2026-05-24 22:56:50 -05:00
1 parent 0a83395a16
commit e935233ba6
5 files changed
+570 -34

No files matched your search

+97
View File
@@ -6,6 +6,103 @@ by [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow
## [Unreleased]
## [0.0.22] — 2026-05-24 — Phase 2.4 impl — Real `compute_fee_for_action` + mock runtime integration tests E2E (10 scenarios)
**🛠️ Phase 2.4 FEES pallet REAL IMPL canonical** — `compute_fee_for_action`
dispatchable real wired via vendor `compute_fee()` pure fn call + storage update
`AccountFees<StorageMap>` saturating arithmetic + event emission canonical. Mock
runtime + 10 integration tests E2E pattern v0.0.18 mirror (Phase 2.1 PROVENANCE).
### Deliverables v0.0.22
**Real dispatchable canonical**:
- `crates/origin-chain-fees/src/lib.rs::pallet::compute_fee_for_action` signature
canonical: `(origin, action, base, hw, sub) -> DispatchResult`
- Flow canonical 5-step per OCAFB-5:
1. `ensure_signed(origin)` canonical
2. Vendor `compute_fee(base, hw, sub, action)` pure fn call canonical (3-step formula)
3. Handle entitlement blocked canonical (`fee == u64::MAX` → `Err(EntitlementLocked)`)
4. `AccountFees<StorageMap>` update saturating arithmetic canonical
5. Emit `FeeCharged` event canonical
- Pure helper `Pallet::<T>::query_fee(action, base, hw, sub) -> u64` para Runtime API
v0.0.23 consumer (wraps vendor compute_fee read-only canonical)
**Consumer pattern canonical**:
- Mathi `OitFeeSchedule` trait consumed CLIENT-SIDE (off-chain) — tx submitter
queries Mathi per-user → assembles tx con `hw + sub` baked → submits canonical
- Pattern análogo Phase 2.1 `attest_asset(origin, ValidationAttestation)` (validation
pre-assembled by Noesis client-side, pallet consumes serialized struct directly)
**Mock runtime canonical (NEW file)**:
- `crates/origin-chain-fees/src/mock.rs` — 80 LOC pattern v0.0.18 mirror
- `construct_runtime!` macro: `System` + `Fees` (minimal testing)
- `frame_system::Config` impl via `derive_impl(TestDefaultConfig)` + `AccountId32`
- `new_test_ext()` helper canonical (`sp_io::TestExternalities` con block 1)
- Helpers `alice_origin`/`alice_account` + `bob_origin`/`bob_account`
**Integration tests canonical E2E (NEW file)**:
- `crates/origin-chain-fees/src/tests_integration.rs` — 290 LOC, **10 tests verde canonical**
**10 integration tests OCAFB-5 flow canonical**:
| # | Scenario | HW | Sub | Action | Expected outcome |
|---|----------|----|----|--------|------------------|
| 1 | `scenario_1_pi5_write_subsidy_90_canonical` | EmbeddedArm | Free | Write | fee=1000 (10% del base 10000, Inmutable #16) |
| 2 | `scenario_2_ultra_write_full_price_canonical` | Ultra | Pro | Write | fee=1500 (base 1000 × 1.5 Pro multiplier) |
| 3 | `scenario_3_read_always_free_inmutable_37_canonical` | Desktop | Free | Read | fee=0 (subsidy 100%, Inmutable #37) |
| 4 | `scenario_4_free_compute_blocked_entitlement_canonical` | Desktop | Free | Compute | `Err(EntitlementLocked)` (Inmutable #37 enforcement) |
| 5 | `scenario_5_pro_compute_unlocked_canonical` | Desktop | Pro | Compute | fee=112 (basis points math) |
| 6 | `scenario_6_ultra_compute_premium_canonical` | Ultra | Ultra | Compute | fee=2000 (base × 2.0 Ultra premium, Inmutable #18) |
| 7 | `scenario_7_storage_accumulates_canonical` | Desktop | Pro | Write × 3 | history.total_paid=3375 + count=3 |
| 8 | `scenario_8_chain_action_ordinal_stable_wire_canonical` | n/a | n/a | wire invariant | Read=0 + Write=1 + Compute=2 + Transfer=3 + roundtrip |
| 9 | `scenario_9_inmutable_16_anti_clasista_lobo_blanco_canonical` | Pi5/Ultra | Free/Ultra | Write × 2 | Pi5 fee 1000 STRICTLY < Ultra fee 20000 (compile-detect) |
| 10 | `scenario_10_5_step_walkthrough_canonical` | EmbeddedArm | Free | Transfer | explicit Pre/Post-flight OCAFB-5 assertions |
**FRAME canonical pattern decision**:
- Events NOT emitted on Err path (FRAME revierte events on dispatch error)
- `EntitlementBlocked` event variant retained en enum para Phase 2.5 future
`with_storage_layer` pattern (preserve events on error vía dispatch transaction)
- Caller infers blocked entitlement from `Err(EntitlementLocked)` return value
### OCAFB sub-decisions status post-v0.0.22
| OCAFB | Sub-decision | Status |
|-------|--------------|--------|
| OCAFB-1 | OitFeeSchedule trait 4-method dyn-compatible | ✅ vendor canonical |
| OCAFB-2 | ChainAction taxonomy source-of-truth en types | ✅ |
| OCAFB-3 | Subsidy matrix Inmutable #16 anti-clasista | ✅ wired + lobo blanco verified |
| OCAFB-4 | Entitlement matrix Inmutable #37 + #18 | ✅ enforced via dispatchable |
| OCAFB-5 | compute_fee formula 3-step canonical | ✅ **REAL IMPL dispatchable** |
| OCAFB-6 | OitFeeScheduleMock test harness | ✅ vendor + mock runtime tests E2E |
| **OCAFB-7** | Pallet-origin-fees consumer Charon | 🚧 **storage + dispatchable + tests verde — Runtime API v0.0.23 next** |
### Verification end-to-end canonical
- ✅ `cargo test -p origin-chain-fees` — **32 tests verde canonical, 0 failures**:
- 10 integration tests E2E (`tests_integration` module)
- 16 vendor copy tests (`fee_schedule::tests` module)
- 4 pallet standalone tests (`tests` module)
- 2 auto-generated (mock genesis + runtime integrity)
- ✅ `cargo test --workspace` — **137 tests verde workspace canonical, 0 failures**
- ✅ Zero new compile errors workspace-wide
- ✅ FRAME-required derives canonical added a `HardwareTier` + `SubscriptionTier` +
`AssetQualityTier` (Encode + Decode + DecodeWithMemTracking + MaxEncodedLen + TypeInfo)
### Inmutable #16 anti-clasista canonical compile-detect
Lobo blanco invariant verified via integration test `scenario_9_inmutable_16_anti_clasista_lobo_blanco_canonical`:
- Pi 5 EmbeddedArm Free Write canonical: fee=1000 (10% del base 10000)
- Ultra Ultra Write canonical: fee=20000 (200% del base)
- Ratio canonical 1:20 — Pi 5 user paga STRICTAMENTE menos que Ultra (David canon
ratificado 2026-05-14 materializado canonical en running code)
### Roadmap canonical post-v0.0.22
| Version | Trigger |
|---------|---------|
| **v0.0.23** | **Runtime API canonical `FeesApi.query_fee_for_action` read-only RPC declaration + impl en runtime → Phase 2.4 COMPLETE 7/7 OCAFB (sesión 3+ shipping ahora)** |
| v0.1.0 | Slice 2e WASM resolved + full testnet Q3 2026 launch |
## [0.0.21] — 2026-05-24 — Phase 2.4 wired — Fees pallet runtime composition Index 8
**🔌 Phase 2.4 FEES pallet WIRED runtime composition canonical** — `origin-chain-fees`