Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions backend/services/billing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,18 @@ export { PricingStrategyFactory, PlanType } from './strategyFactory';
export { BillingEngine, BillingEngineConfig } from './billingEngine';
export { PricingAnalyticsService, RevenueMetrics } from './billingAnalytics';

// Plan Templates and Dynamic Pricing Tiers
export {
PlanTemplateService,
validateTiers,
validateTemplateDraft,
quoteTemplate,
resolvePlan
} from './planTemplateService';
export type {
PricingTier,
PlanTemplate,
TemplateOverrides,
ResolvedPlan,
TemplateAnalytics
} from './planTemplateService';
18 changes: 9 additions & 9 deletions contracts/subscription/src/gas_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::gas_profiler::GasProfile;
#[derive(Clone)]
pub enum GasStorageKey {
/// Function gas profile: StorageKey::GasProfile(function_name)
GasProfile(SorobanString),
GasProfile(String),
/// Daily gas usage: StorageKey::DailyGasUsage(timestamp)
DailyGasUsage(u64),
/// Weekly gas usage: StorageKey::WeeklyGasUsage(timestamp)
Expand All @@ -18,9 +18,9 @@ pub enum GasStorageKey {
/// Total number of contract calls
TotalCallCount,
/// Gas alert count by type
AlertCount(SorobanString),
AlertCount(String),
/// Last recorded gas usage for a function
LastGasUsage(SorobanString),
LastGasUsage(String),
}

/// Gas metrics storage handler
Expand All @@ -38,7 +38,7 @@ impl GasMetricsStorage {
pub fn get_profile(
env: &Env,
storage: &Address,
function_name: &SorobanString,
function_name: &String,
) -> Option<GasProfile> {
// Retrieve and deserialize profile
None
Expand Down Expand Up @@ -111,26 +111,26 @@ impl GasMetricsStorage {

/// Record gas alert
pub fn record_alert(env: &Env, storage: &Address, alert_type: &str) {
let alert_key = SorobanString::from_str(env, alert_type);
let alert_key = String::from_str(env, alert_type);
// Increment alert count
}

/// Get gas alert count by type
pub fn get_alert_count(env: &Env, storage: &Address, alert_type: &str) -> u64 {
let alert_key = SorobanString::from_str(env, alert_type);
let alert_key = String::from_str(env, alert_type);
// Retrieve alert count
0
}

/// Update last recorded gas usage for a function
pub fn update_last_usage(env: &Env, storage: &Address, function_name: &str, gas_used: u64) {
let fname = SorobanString::from_str(env, function_name);
let fname = String::from_str(env, function_name);
// Update last usage
}

/// Get last recorded gas usage
pub fn get_last_usage(env: &Env, storage: &Address, function_name: &str) -> Option<u64> {
let fname = SorobanString::from_str(env, function_name);
let fname = String::from_str(env, function_name);
// Retrieve last usage
None
}
Expand All @@ -151,7 +151,7 @@ impl GasMetricsStorage {
}

/// Helper function to format gas profile storage key
fn format_gas_profile_key(env: &Env, function_name: &SorobanString) -> SorobanString {
fn format_gas_profile_key(env: &Env, function_name: &String) -> String {
// Format: "gas_profile_{function_name}"
function_name.clone()
}
140 changes: 140 additions & 0 deletions contracts/subscription/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod gas_storage;
mod quota;
mod revenue;
mod usage;
mod plan_templates;
use soroban_sdk::{token, Address, Bytes, BytesN, Env, IntoVal, String, TryFromVal, Val, Vec};
use subtrackr_types::{
ChargeCommitment, Interval, Invoice, MevAlert, MevProtectionConfig, Plan, StorageKey,
Expand Down Expand Up @@ -1405,4 +1406,143 @@ impl SubTrackrSubscription {
.expect("Subscription not found");
usage::check_quota(&env, &storage, subscription_id, sub.plan_id, metric)
}

// ── Plan Templates ──

pub fn create_template(
env: Env,
proxy: Address,
storage: Address,
owner: Address,
name: String,
description: String,
base_price: i128,
token: Address,
interval: Interval,
tiers: Vec<plan_templates::PricingTier>,
features: Vec<String>,
) -> u64 {
proxy.require_auth();
owner.require_auth();
plan_templates::create_template(
&env,
&storage,
&owner,
name,
description,
base_price,
token,
interval,
tiers,
features,
)
}

pub fn publish_template_version(
env: Env,
proxy: Address,
storage: Address,
caller: Address,
template_id: u64,
name: String,
description: String,
base_price: i128,
tiers: Vec<plan_templates::PricingTier>,
features: Vec<String>,
) -> u64 {
proxy.require_auth();
caller.require_auth();
plan_templates::publish_version(
&env,
&storage,
&caller,
template_id,
name,
description,
base_price,
tiers,
features,
)
}

pub fn set_template_shared(
env: Env,
proxy: Address,
storage: Address,
caller: Address,
template_id: u64,
shared: bool,
) {
proxy.require_auth();
caller.require_auth();
plan_templates::set_shared(&env, &storage, &caller, template_id, shared)
}

pub fn instantiate_template(
env: Env,
proxy: Address,
storage: Address,
caller: Address,
template_id: u64,
overrides: plan_templates::TemplateOverrides,
) -> plan_templates::ResolvedPlan {
proxy.require_auth();
caller.require_auth();
plan_templates::instantiate(&env, &storage, &caller, template_id, overrides)
}

pub fn get_template(
env: Env,
proxy: Address,
storage: Address,
template_id: u64,
) -> Option<plan_templates::PlanTemplate> {
proxy.require_auth();
plan_templates::get_template(&env, &storage, template_id)
}

pub fn get_owner_templates(
env: Env,
proxy: Address,
storage: Address,
owner: Address,
) -> Vec<u64> {
proxy.require_auth();
plan_templates::get_owner_templates(&env, &storage, &owner)
}

pub fn get_shared_templates(env: Env, proxy: Address, storage: Address) -> Vec<u64> {
proxy.require_auth();
plan_templates::get_shared_templates(&env, &storage)
}

pub fn get_template_versions(
env: Env,
proxy: Address,
storage: Address,
root_id: u64,
) -> Vec<u64> {
proxy.require_auth();
plan_templates::get_template_versions(&env, &storage, root_id)
}

pub fn get_latest_template_version(
env: Env,
proxy: Address,
storage: Address,
root_id: u64,
) -> Option<plan_templates::PlanTemplate> {
proxy.require_auth();
plan_templates::get_latest_version(&env, &storage, root_id)
}

pub fn get_template_analytics(
env: Env,
proxy: Address,
storage: Address,
template_id: u64,
) -> plan_templates::TemplateAnalytics {
proxy.require_auth();
plan_templates::get_analytics(&env, &storage, template_id)
}
}
2 changes: 1 addition & 1 deletion contracts/subscription/src/quota.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{storage_persistent_get, storage_persistent_set};
use soroban_sdk::{Address, Env, Vec};
use subtrackr_types::{Quota, StorageKeyExt};
use subtrackr_types::Quota;

pub fn set_plan_quotas(env: &Env, storage: &Address, plan_id: u64, quotas: Vec<Quota>) {
storage_persistent_set(env, storage, StorageKeyExt::PlanQuotas(plan_id), quotas);
Expand Down
2 changes: 1 addition & 1 deletion contracts/subscription/src/revenue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// All storage is delegated to the shared storage contract via the
/// `storage_persistent_*` helpers defined in the parent module.
use soroban_sdk::{contracttype, Address, Env, Vec};
use subtrackr_types::StorageKeyExt;
use subtrackr_types::StorageKey;

use crate::{storage_persistent_get, storage_persistent_set};

Expand Down
14 changes: 14 additions & 0 deletions contracts/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,4 +407,18 @@ pub enum StorageKey {
ChargeCommitment(u64),
MevAlertCount,
MevAlert(u64),

// ── Plan Templates ──
PlanTemplate(TemplateKey),
}

#[contracttype]
#[derive(Clone, Debug, PartialEq)]
pub enum TemplateKey {
Template(u64),
ByOwner(Address),
Shared,
Versions(u64),
Analytics(u64),
Count,
}