feat(fees,genesis): FeesApi account-aligned query + 250M Foundation→vault og/gvtry
Dos endurecimientos pre-mainnet (leftovers del remediation roadmap): 1. genesis vault (#16/CHN-4): el preset mainnet asigna el 25% Foundation Treasury (250M OGC) al VAULT de governance (og/gvtry, GovernanceTreasuryPalletId), NO a una cuenta key-controlada. Es la MISMA cuenta de la que treasury_disbursement gasta (gated por governance council) y que emission/staking alimentan → el treasury queda DAO-governed desde el bloque 0, materializando "Foundation Treasury → DAO governed (CHN-4)". El placeholder FNDT queda SOLO como sudo_key interim hasta el sunset (DC ORIGIN_CHAIN_GOVERNANCE_SUNSET_V1). Las allocations BM V2 (40/25/15/15/5 = 1B) no cambian de monto. 2. FeesApi alignment: nuevo método query_fee_for_account(action, base, account) que estima el fee con el TierProfile REAL on-chain del account (storage TierProfiles, ValueQuery default Desktop+Free), NO caller-supplied — alineado con el fee-path vivo OriginFeeAdapter (FIX-6 Stage 2a). Cierra el "el cliente adivinaba hw/sub": la estimación off-chain ahora usa la misma fórmula sobre el MISMO tier que cobra la cadena. Método aditivo al Runtime API ⇒ TRANSACTION_VERSION 1 intacto. RUNTIME_VERSION 4→5 (nueva metadata de FeesApi). 268 workspace tests verde (native, SKIP_WASM_BUILD — WASM VPS-gated), 0 regresión. Test sella que query_fee_for_account usa el perfil real (EmbeddedArm piso < default Desktop). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
112747ab44
commit
8e72496901
4 files changed
+96
-12
No files matched your search
@@ -99,6 +99,19 @@ sp_api::decl_runtime_apis! {
|
||||
hw: origin_chain_types::HardwareTier,
|
||||
sub: origin_chain_types::SubscriptionTier,
|
||||
) -> u64;
|
||||
|
||||
/// Query fee canonical para `(action, base)` usando el `TierProfile`
|
||||
/// REAL on-chain del `account` (storage `TierProfiles`, NUNCA
|
||||
/// caller-supplied — alineado con el fee-path vivo `OriginFeeAdapter`).
|
||||
/// Un account sin perfil asignado usa el default conservador
|
||||
/// (`Desktop + Free`, ValueQuery). Read-only canonical (off-chain RPC).
|
||||
/// Cierra el gap "el cliente adivinaba hw/sub": ahora la estimación es
|
||||
/// la misma fórmula sobre el MISMO tier que cobra la cadena.
|
||||
fn query_fee_for_account(
|
||||
action: origin_chain_types::ChainAction,
|
||||
base: u64,
|
||||
account: origin_chain_types::AccountId,
|
||||
) -> u64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,6 +363,16 @@ pub mod pallet {
|
||||
crate::compute_fee(base, hw, sub, action)
|
||||
}
|
||||
|
||||
/// Igual que [`Self::query_fee`] pero lee el `TierProfile` REAL on-chain
|
||||
/// del `account` (storage `TierProfiles`, ValueQuery → default conservador
|
||||
/// `Desktop + Free` si no hay perfil). Alinea la estimación off-chain con
|
||||
/// el tier que el `OriginFeeAdapter` realmente cobra (FIX-6 Stage 2a) —
|
||||
/// nunca caller-supplied, cierra el tier-guessing del cliente.
|
||||
pub fn query_fee_for_account(action: ChainAction, base: u64, account: &T::AccountId) -> u64 {
|
||||
let profile = TierProfiles::<T>::get(account);
|
||||
crate::compute_fee(base, profile.hw, profile.sub, action)
|
||||
}
|
||||
|
||||
/// FIX-6 Stage 2a: cuenta del subsidy pool `og/subsy` (determinística,
|
||||
/// keyless — derivada del MISMO PalletId que alimenta la emisión).
|
||||
pub fn subsidy_account() -> T::AccountId {
|
||||
|
||||
@@ -104,6 +104,43 @@ fn default_profile_es_desktop_free_conservador() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn query_fee_for_account_usa_el_tier_profile_real_on_chain() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let base = 1_000u64;
|
||||
let action = origin_chain_types::ChainAction::Write;
|
||||
|
||||
// Sin perfil asignado → default conservador Desktop+Free (igual que
|
||||
// query_fee con Desktop+Free, NO caller-supplied).
|
||||
let default_fee =
|
||||
Fees::query_fee(action, base, HardwareTier::Desktop, SubscriptionTier::Free);
|
||||
assert_eq!(
|
||||
Fees::query_fee_for_account(action, base, &alice_account()),
|
||||
default_fee,
|
||||
"account sin perfil usa el default Desktop+Free"
|
||||
);
|
||||
|
||||
// Con perfil EmbeddedArm+Free → query_fee_for_account refleja el piso #16
|
||||
// (subsidy alta), distinto del default Desktop.
|
||||
set_profile(
|
||||
alice_account(),
|
||||
HardwareTier::EmbeddedArm,
|
||||
SubscriptionTier::Free,
|
||||
);
|
||||
let arm_fee =
|
||||
Fees::query_fee(action, base, HardwareTier::EmbeddedArm, SubscriptionTier::Free);
|
||||
assert_eq!(
|
||||
Fees::query_fee_for_account(action, base, &alice_account()),
|
||||
arm_fee,
|
||||
"account con perfil EmbeddedArm usa ese tier real"
|
||||
);
|
||||
assert!(
|
||||
arm_fee < default_fee,
|
||||
"EmbeddedArm (piso #16) paga menos que el default Desktop"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_tier_profile_es_root_only() {
|
||||
new_test_ext().execute_with(|| {
|
||||
|
||||
Reference in new issue
Block a user