Smart Contract
UsageBasedSubscriptions
A.6daee039a7b9c2f0.UsageBasedSubscriptions
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import FlareFDCTriggers from 0x6daee039a7b9c2f0
4import DeFiActions from 0x92195d814edf9cb0
5
6/// UsageBasedSubscriptions: Dynamic pricing based on real-time usage from LiteLLM via Flare Data Connector
7/// Automatically adjusts subscription costs and processes payments based on actual consumption
8access(all) contract UsageBasedSubscriptions {
9
10 /// Events
11 access(all) event SubscriptionCreated(vaultId: UInt64, owner: Address, provider: Address)
12 access(all) event UsageDataReceived(vaultId: UInt64, usage: UsageReport, source: String)
13 access(all) event PriceCalculated(vaultId: UInt64, basePrice: UFix64, usageMultiplier: UFix64, finalPrice: UFix64)
14 access(all) event PaymentProcessed(vaultId: UInt64, amount: UFix64, provider: Address)
15 access(all) event AutomaticPaymentProcessed(vaultId: UInt64, amount: UFix64, provider: Address, totalPaidToDate: UFix64)
16 access(all) event EntitlementUpdated(vaultId: UInt64, withdrawLimit: UFix64, validUntil: UFix64)
17 access(all) event UsageTierChanged(vaultId: UInt64, oldTier: String, newTier: String)
18
19 /// Storage paths
20 access(all) let VaultStoragePath: StoragePath
21 access(all) let VaultPublicPath: PublicPath
22 access(all) let ProviderStoragePath: StoragePath
23
24 /// Global registry
25 access(all) var totalVaults: UInt64
26 access(all) let vaultRegistry: {UInt64: Address}
27
28 /// Pricing tiers based on usage
29 access(all) struct PricingTier {
30 access(all) let name: String
31 access(all) let minUsage: UInt64 // Min API calls/tokens
32 access(all) let maxUsage: UInt64 // Max API calls/tokens
33 access(all) let pricePerUnit: UFix64 // Price per 1000 tokens/calls
34 access(all) let discountRate: UFix64 // Volume discount (0.0 - 1.0)
35
36 init(name: String, minUsage: UInt64, maxUsage: UInt64, pricePerUnit: UFix64, discountRate: UFix64) {
37 self.name = name
38 self.minUsage = minUsage
39 self.maxUsage = maxUsage
40 self.pricePerUnit = pricePerUnit
41 self.discountRate = discountRate
42 }
43 }
44
45 /// Usage report from LiteLLM via FDC
46 access(all) struct UsageReport {
47 access(all) let timestamp: UFix64
48 access(all) let period: String // "daily", "weekly", "monthly"
49 access(all) let totalTokens: UInt64 // Total tokens consumed
50 access(all) let apiCalls: UInt64 // Number of API calls
51 access(all) let models: {String: UInt64} // Usage by model (gpt-4, claude, etc)
52 access(all) let costEstimate: UFix64 // Provider's cost estimate
53 access(all) let metadata: {String: String}
54
55 init(
56 timestamp: UFix64,
57 period: String,
58 totalTokens: UInt64,
59 apiCalls: UInt64,
60 models: {String: UInt64},
61 costEstimate: UFix64,
62 metadata: {String: String}
63 ) {
64 self.timestamp = timestamp
65 self.period = period
66 self.totalTokens = totalTokens
67 self.apiCalls = apiCalls
68 self.models = models
69 self.costEstimate = costEstimate
70 self.metadata = metadata
71 }
72 }
73
74 /// Entitlement types
75 access(all) enum EntitlementType: UInt8 {
76 access(all) case fixed // Fixed withdrawal limit set by user
77 access(all) case dynamic // Grows with usage as long as vault is funded
78 }
79
80 /// Dynamic entitlement for automated withdrawals
81 access(all) struct Entitlement {
82 access(all) let vaultId: UInt64
83 access(all) var withdrawLimit: UFix64 // Max amount provider can withdraw
84 access(all) var usedAmount: UFix64 // Amount already withdrawn
85 access(all) var validUntil: UFix64 // Expiration timestamp
86 access(all) var lastUpdate: UFix64 // Last FDC update
87 access(all) var isActive: Bool
88 access(all) let entitlementType: EntitlementType // Fixed or Dynamic
89 access(all) let fixedLimit: UFix64 // Original fixed limit (if fixed type)
90
91 access(all) fun updateLimit(newLimit: UFix64, validityPeriod: UFix64) {
92 // For fixed entitlements, never exceed the original fixed limit
93 if self.entitlementType == EntitlementType.fixed {
94 self.withdrawLimit = newLimit > self.fixedLimit ? self.fixedLimit : newLimit
95 } else {
96 // Dynamic entitlements can grow with usage
97 self.withdrawLimit = newLimit
98 }
99
100 self.validUntil = getCurrentBlock().timestamp + validityPeriod
101 self.lastUpdate = getCurrentBlock().timestamp
102 }
103
104 access(all) fun recordWithdrawal(amount: UFix64) {
105 self.usedAmount = self.usedAmount + amount
106 }
107
108 access(all) fun getRemainingAllowance(): UFix64 {
109 if getCurrentBlock().timestamp > self.validUntil {
110 return 0.0
111 }
112 return self.withdrawLimit > self.usedAmount
113 ? self.withdrawLimit - self.usedAmount
114 : 0.0
115 }
116
117 init(vaultId: UInt64, entitlementType: EntitlementType, initialLimit: UFix64, validityPeriod: UFix64) {
118 self.vaultId = vaultId
119 self.entitlementType = entitlementType
120 self.fixedLimit = entitlementType == EntitlementType.fixed ? initialLimit : 0.0
121 self.withdrawLimit = initialLimit
122 self.usedAmount = 0.0
123 self.validUntil = getCurrentBlock().timestamp + validityPeriod
124 self.lastUpdate = getCurrentBlock().timestamp
125 self.isActive = true
126 }
127 }
128
129 /// Usage-based subscription vault
130 access(all) resource SubscriptionVault {
131 access(all) let id: UInt64
132 access(all) let customer: Address
133 access(all) let provider: Address
134 access(all) let serviceName: String
135
136 // Funding
137 access(self) let vault: @{FungibleToken.Vault}
138
139 // Usage tracking
140 access(all) var currentUsage: UsageReport?
141 access(all) var usageHistory: [UsageReport]
142 access(all) var currentTier: PricingTier
143
144 // Cumulative usage tracking for differential payments
145 access(all) var lastPaidTokens: UInt64 // Tokens we've already paid for
146 access(all) var lastPaidRequests: UInt64 // Requests we've already paid for
147 access(all) var totalPaidAmount: UFix64 // Total FLOW paid to provider
148 access(all) var lastOracleUpdate: UFix64 // Timestamp of last oracle confirmation
149
150 // Dynamic pricing
151 access(all) var basePrice: UFix64
152 access(all) var usageMultiplier: UFix64
153 access(all) var currentPrice: UFix64
154
155 // Entitlements
156 access(all) var entitlement: Entitlement
157
158 // Settings
159 access(all) var autoPay: Bool
160 access(all) var maxMonthlySpend: UFix64
161
162 // Selected AI models (max 3)
163 access(all) let selectedModels: [String] // Model IDs like ["gpt-4", "claude-3-sonnet"]
164 access(all) let modelPricing: {String: UFix64} // Model-specific pricing overrides
165
166 /// Process usage data from FDC and update pricing
167 access(all) fun processUsageData(usage: UsageReport) {
168 // Store usage report
169 self.currentUsage = usage
170 self.usageHistory.append(usage)
171
172 // Calculate NEW usage since last payment (differential)
173 let newTokens = usage.totalTokens > self.lastPaidTokens ? usage.totalTokens - self.lastPaidTokens : 0
174 let newRequests = usage.apiCalls > self.lastPaidRequests ? usage.apiCalls - self.lastPaidRequests : 0
175
176 log("📊 Processing differential usage:")
177 log(" Total tokens: ".concat(usage.totalTokens.toString()).concat(" (+").concat(newTokens.toString()).concat(" new)"))
178 log(" Total requests: ".concat(usage.apiCalls.toString()).concat(" (+").concat(newRequests.toString()).concat(" new)"))
179 log(" Last paid tokens: ".concat(self.lastPaidTokens.toString()))
180
181 // Only process payment if there's NEW usage
182 if UInt64(newTokens) > 0 || UInt64(newRequests) > 0 {
183 // Update pricing tier based on TOTAL usage
184 let newTier = UsageBasedSubscriptions.calculateTier(usage.totalTokens)
185 if newTier.name != self.currentTier.name {
186 emit UsageTierChanged(
187 vaultId: self.id,
188 oldTier: self.currentTier.name,
189 newTier: newTier.name
190 )
191 self.currentTier = newTier
192 }
193
194 // Calculate price for NEW usage only
195 let newUsageReport = UsageReport(
196 timestamp: usage.timestamp,
197 period: usage.period,
198 totalTokens: UInt64(newTokens),
199 apiCalls: UInt64(newRequests),
200 models: usage.models,
201 costEstimate: 0.0, // Will be calculated
202 metadata: usage.metadata
203 )
204
205 self.calculateDynamicPrice(newUsageReport)
206
207 // Process automatic payment for new usage
208 self.processAutomaticPayment(newUsageAmount: self.currentPrice)
209
210 // Update paid tracking
211 self.lastPaidTokens = usage.totalTokens
212 self.lastPaidRequests = usage.apiCalls
213 self.lastOracleUpdate = getCurrentBlock().timestamp
214 }
215
216 emit UsageDataReceived(
217 vaultId: self.id,
218 usage: usage,
219 source: "LiteLLM via FDC"
220 )
221 }
222
223 /// Calculate dynamic price based on usage
224 access(self) fun calculateDynamicPrice(_ usage: UsageReport) {
225 // Base calculation: tokens * price per unit
226 let tokenThousands = UFix64(usage.totalTokens) / 1000.0
227 var calculatedPrice = tokenThousands * self.currentTier.pricePerUnit
228
229 // Apply volume discount
230 calculatedPrice = calculatedPrice * (1.0 - self.currentTier.discountRate)
231
232 // Apply model-specific multipliers based on selected models
233 var modelMultiplier = 1.0
234 var modelCount = 0
235
236 for model in usage.models.keys {
237 // Only apply pricing for selected models
238 if self.selectedModels.contains(model) {
239 let multiplier = self.modelPricing[model] ?? 1.0
240 modelMultiplier = modelMultiplier + multiplier
241 modelCount = modelCount + 1
242 }
243 }
244
245 // Average the multipliers if multiple models were used
246 if modelCount > 0 {
247 modelMultiplier = modelMultiplier / UFix64(modelCount)
248 }
249
250 self.usageMultiplier = modelMultiplier
251 self.currentPrice = calculatedPrice * modelMultiplier
252
253 emit PriceCalculated(
254 vaultId: self.id,
255 basePrice: self.basePrice,
256 usageMultiplier: self.usageMultiplier,
257 finalPrice: self.currentPrice
258 )
259 }
260
261 /// Update entitlement for provider withdrawals
262 access(self) fun updateEntitlement() {
263 let withdrawLimit = self.currentPrice
264 let validityPeriod = 86400.0 * 30.0 // 30 days
265
266 self.entitlement.updateLimit(
267 newLimit: withdrawLimit,
268 validityPeriod: validityPeriod
269 )
270
271 emit EntitlementUpdated(
272 vaultId: self.id,
273 withdrawLimit: withdrawLimit,
274 validUntil: self.entitlement.validUntil
275 )
276 }
277
278 /// Provider withdraws based on entitlement
279 access(all) fun withdrawWithEntitlement(amount: UFix64): @{FungibleToken.Vault} {
280 // Check entitlement allowance
281 let remainingAllowance = self.entitlement.getRemainingAllowance()
282 assert(amount <= remainingAllowance, message: "Amount exceeds entitlement allowance")
283 assert(amount <= self.vault.balance, message: "Insufficient vault balance")
284
285 let payment <- self.vault.withdraw(amount: amount)
286 self.entitlement.recordWithdrawal(amount: amount)
287
288 emit PaymentProcessed(
289 vaultId: self.id,
290 amount: amount,
291 provider: self.provider
292 )
293
294 return <- payment
295 }
296
297 /// Process automatic payment to provider based on new usage
298 access(self) fun processAutomaticPayment(newUsageAmount: UFix64) {
299 // Check if automatic payments are enabled
300 if !self.autoPay {
301 log("⏸️ Auto-pay disabled, skipping automatic payment")
302 return
303 }
304
305 // Check if vault has sufficient balance
306 if self.vault.balance < newUsageAmount {
307 log("⚠️ Insufficient vault balance for automatic payment")
308 log(" Required: ".concat(newUsageAmount.toString()).concat(" FLOW"))
309 log(" Available: ".concat(self.vault.balance.toString()).concat(" FLOW"))
310 return
311 }
312
313 // Check monthly spending limits
314 if self.totalPaidAmount + newUsageAmount > self.maxMonthlySpend {
315 log("⚠️ Monthly spending limit exceeded, skipping automatic payment")
316 log(" Would exceed limit by: ".concat((self.totalPaidAmount + newUsageAmount - self.maxMonthlySpend).toString()).concat(" FLOW"))
317 return
318 }
319
320 // Process automatic payment
321 log("💰 Processing automatic payment:")
322 log(" Amount: ".concat(newUsageAmount.toString()).concat(" FLOW"))
323 log(" Provider: ".concat(self.provider.toString()))
324
325 // Transfer funds directly to provider
326 let payment <- self.vault.withdraw(amount: newUsageAmount)
327
328 // Get provider's Flow vault and deposit payment
329 let providerAccount = getAccount(self.provider)
330 let providerReceiver = providerAccount.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!
331 let receiverRef = providerReceiver.borrow()!
332 receiverRef.deposit(from: <- payment)
333
334 // Update tracking
335 self.totalPaidAmount = self.totalPaidAmount + newUsageAmount
336 self.entitlement.recordWithdrawal(amount: newUsageAmount)
337
338 emit PaymentProcessed(
339 vaultId: self.id,
340 amount: newUsageAmount,
341 provider: self.provider
342 )
343
344 emit AutomaticPaymentProcessed(
345 vaultId: self.id,
346 amount: newUsageAmount,
347 provider: self.provider,
348 totalPaidToDate: self.totalPaidAmount
349 )
350
351 log("✅ Automatic payment completed successfully")
352 }
353
354 /// Deposit funds to vault
355 access(all) fun deposit(from: @{FungibleToken.Vault}) {
356 self.vault.deposit(from: <- from)
357 }
358
359 /// Get vault balance
360 access(all) fun getBalance(): UFix64 {
361 return self.vault.balance
362 }
363
364 /// Get current pricing info
365 access(all) fun getPricingInfo(): {String: AnyStruct} {
366 return {
367 "currentTier": self.currentTier.name,
368 "basePrice": self.basePrice,
369 "usageMultiplier": self.usageMultiplier,
370 "currentPrice": self.currentPrice,
371 "remainingEntitlement": self.entitlement.getRemainingAllowance()
372 }
373 }
374
375 /// Get complete vault information for UI display
376 access(all) fun getVaultInfo(): {String: AnyStruct} {
377 return {
378 "vaultId": self.id,
379 "owner": self.owner,
380 "provider": self.provider,
381 "serviceName": self.serviceName,
382 "balance": self.vault.balance,
383 "selectedModels": self.selectedModels,
384 "modelPricing": self.modelPricing,
385 "entitlementType": self.entitlement.entitlementType.rawValue,
386 "withdrawLimit": self.entitlement.withdrawLimit,
387 "usedAmount": self.entitlement.usedAmount,
388 "validUntil": self.entitlement.validUntil,
389 "isActive": self.entitlement.isActive,
390 "currentTier": self.currentTier.name,
391 "basePrice": self.basePrice,
392 "currentPrice": self.currentPrice,
393 "autoPay": self.autoPay,
394 "maxMonthlySpend": self.maxMonthlySpend,
395 "lastPaidTokens": self.lastPaidTokens,
396 "lastPaidRequests": self.lastPaidRequests,
397 "totalPaidAmount": self.totalPaidAmount,
398 "lastOracleUpdate": self.lastOracleUpdate
399 }
400 }
401
402 init(
403 owner: Address,
404 provider: Address,
405 serviceName: String,
406 vault: @{FungibleToken.Vault},
407 entitlementType: EntitlementType,
408 initialWithdrawLimit: UFix64,
409 validityPeriod: UFix64,
410 selectedModels: [String]
411 ) {
412 self.id = UsageBasedSubscriptions.totalVaults
413 UsageBasedSubscriptions.totalVaults = UsageBasedSubscriptions.totalVaults + 1
414
415 self.customer = owner
416 self.provider = provider
417 self.serviceName = serviceName
418 self.vault <- vault
419
420 self.currentUsage = nil
421 self.usageHistory = []
422 self.currentTier = UsageBasedSubscriptions.getDefaultTier()
423
424 // Initialize cumulative usage tracking
425 self.lastPaidTokens = 0
426 self.lastPaidRequests = 0
427 self.totalPaidAmount = 0.0
428 self.lastOracleUpdate = 0.0
429
430 self.basePrice = 10.0 // $10 base
431 self.usageMultiplier = 1.0
432 self.currentPrice = 10.0
433
434 // Create entitlement with user-specified settings
435 self.entitlement = Entitlement(
436 vaultId: self.id,
437 entitlementType: entitlementType,
438 initialLimit: initialWithdrawLimit,
439 validityPeriod: validityPeriod
440 )
441
442 self.autoPay = true
443 self.maxMonthlySpend = 1000.0
444
445 // Initialize selected models and pricing
446 self.selectedModels = selectedModels
447 self.modelPricing = {}
448
449 // Validate model selection (max 3 models)
450 assert(self.selectedModels.length > 0, message: "At least 1 model must be selected")
451 assert(self.selectedModels.length <= 3, message: "Maximum 3 models allowed per subscription")
452
453 // Set up model-specific pricing overrides
454 for model in self.selectedModels {
455 if model == "gpt-4" || model == "claude-3-opus" {
456 self.modelPricing[model] = 1.5 // Premium models cost 50% more
457 } else if model == "gpt-3.5-turbo" || model == "claude-3-haiku" {
458 self.modelPricing[model] = 0.8 // Budget models cost 20% less
459 } else {
460 self.modelPricing[model] = 1.0 // Standard pricing
461 }
462 }
463
464 UsageBasedSubscriptions.vaultRegistry[self.id] = owner
465 }
466 }
467
468 /// FDC Handler for LiteLLM usage data
469 access(all) resource LiteLLMUsageHandler: FlareFDCTriggers.TriggerHandler {
470 access(self) var isHandlerActive: Bool
471
472 access(all) fun handleTrigger(trigger: FlareFDCTriggers.FDCTrigger): Bool {
473 // Extract usage data from FDC trigger
474 let vaultId = trigger.payload["vaultId"] as? UInt64 ?? 0
475 let totalTokens = trigger.payload["totalTokens"] as? UInt64 ?? 0
476 let apiCalls = trigger.payload["apiCalls"] as? UInt64 ?? 0
477
478 // Create usage report
479 let models: {String: UInt64} = {}
480 if let modelUsage = trigger.payload["models"] as? {String: UInt64} {
481 for key in modelUsage.keys {
482 models[key] = modelUsage[key]!
483 }
484 }
485
486 let usage = UsageReport(
487 timestamp: trigger.timestamp,
488 period: trigger.payload["period"] as? String ?? "daily",
489 totalTokens: totalTokens,
490 apiCalls: apiCalls,
491 models: models,
492 costEstimate: trigger.payload["costEstimate"] as? UFix64 ?? 0.0,
493 metadata: {}
494 )
495
496 // Update subscription vault
497 if let ownerAddress = UsageBasedSubscriptions.vaultRegistry[vaultId] {
498 // Vault access should be done via transactions with proper authorization
499 log("Usage update requested for vault ID: ".concat(vaultId.toString()))
500 return true
501 }
502
503 return false
504 }
505
506 access(all) fun getSupportedTriggerTypes(): [FlareFDCTriggers.TriggerType] {
507 return [
508 FlareFDCTriggers.TriggerType.DefiProtocolEvent
509 ]
510 }
511
512 access(all) fun isActive(): Bool {
513 return self.isHandlerActive
514 }
515
516 init() {
517 self.isHandlerActive = true
518 }
519 }
520
521 /// Provider resource for managing subscriptions
522 access(all) resource ServiceProvider {
523 access(all) let address: Address
524 access(all) let serviceName: String
525 access(all) var totalEarnings: UFix64
526 access(all) var activeSubscriptions: {UInt64: Bool}
527
528 /// Withdraw from customer vault based on entitlement
529 access(all) fun collectPayment(vaultId: UInt64, amount: UFix64): @{FungibleToken.Vault}? {
530 if let ownerAddress = UsageBasedSubscriptions.vaultRegistry[vaultId] {
531 // Vault access should be done via transactions with proper authorization
532 log("Payment collection requested for vault ID: ".concat(vaultId.toString()))
533 // Return nil for now - should be handled via transactions
534 return nil
535 }
536 return nil
537 }
538
539 init(address: Address, serviceName: String) {
540 self.address = address
541 self.serviceName = serviceName
542 self.totalEarnings = 0.0
543 self.activeSubscriptions = {}
544 }
545 }
546
547 /// Public functions
548
549 /// Create a new subscription vault with entitlement settings
550 access(all) fun createSubscriptionVault(
551 owner: Address,
552 provider: Address,
553 serviceName: String,
554 initialDeposit: @{FungibleToken.Vault},
555 entitlementType: EntitlementType,
556 initialWithdrawLimit: UFix64,
557 validityPeriod: UFix64,
558 selectedModels: [String]
559 ): @SubscriptionVault {
560 let vault <- create SubscriptionVault(
561 owner: owner,
562 provider: provider,
563 serviceName: serviceName,
564 vault: <- initialDeposit,
565 entitlementType: entitlementType,
566 initialWithdrawLimit: initialWithdrawLimit,
567 validityPeriod: validityPeriod,
568 selectedModels: selectedModels
569 )
570
571 emit SubscriptionCreated(vaultId: vault.id, owner: owner, provider: provider)
572
573 return <- vault
574 }
575
576 /// Get vault storage path
577 access(all) fun getVaultStoragePath(): StoragePath {
578 return self.VaultStoragePath
579 }
580
581 /// Get all vault IDs for a user
582 access(all) fun getUserVaultIds(owner: Address): [UInt64] {
583 let vaultIds: [UInt64] = []
584
585 for vaultId in self.vaultRegistry.keys {
586 if self.vaultRegistry[vaultId] == owner {
587 vaultIds.append(vaultId)
588 }
589 }
590
591 return vaultIds
592 }
593
594 /// Get vault information by vault ID
595 access(all) fun getVaultInfo(vaultId: UInt64): {String: AnyStruct}? {
596 if let ownerAddress = self.vaultRegistry[vaultId] {
597 // Vault info access should be done via transactions
598 return {"vaultId": vaultId, "owner": ownerAddress}
599 }
600 return nil
601 }
602
603 /// Calculate pricing tier based on usage
604 access(all) fun calculateTier(_ totalTokens: UInt64): PricingTier {
605 let tiers = self.getPricingTiers()
606
607 for tier in tiers {
608 if totalTokens >= tier.minUsage && totalTokens <= tier.maxUsage {
609 return tier
610 }
611 }
612
613 return self.getDefaultTier()
614 }
615
616 /// Get pricing tiers
617 access(all) fun getPricingTiers(): [PricingTier] {
618 return [
619 PricingTier(name: "Starter", minUsage: 0, maxUsage: 100000, pricePerUnit: 0.02, discountRate: 0.0),
620 PricingTier(name: "Growth", minUsage: 100001, maxUsage: 1000000, pricePerUnit: 0.015, discountRate: 0.1),
621 PricingTier(name: "Scale", minUsage: 1000001, maxUsage: 10000000, pricePerUnit: 0.01, discountRate: 0.2),
622 PricingTier(name: "Enterprise", minUsage: 10000001, maxUsage: UInt64.max, pricePerUnit: 0.008, discountRate: 0.3)
623 ]
624 }
625
626 /// Get default tier
627 access(all) fun getDefaultTier(): PricingTier {
628 return PricingTier(name: "Starter", minUsage: 0, maxUsage: 100000, pricePerUnit: 0.02, discountRate: 0.0)
629 }
630
631 /// Helper function to convert time periods to seconds
632 access(all) fun convertToSeconds(amount: UInt64, unit: String): UFix64 {
633 switch unit {
634 case "hours":
635 return UFix64(amount) * 3600.0
636 case "days":
637 return UFix64(amount) * 86400.0
638 case "months":
639 return UFix64(amount) * 2592000.0 // 30 days
640 default:
641 return UFix64(amount) * 86400.0 // Default to days
642 }
643 }
644
645 /// Create service provider
646 access(all) fun createServiceProvider(address: Address, serviceName: String): @ServiceProvider {
647 return <- create ServiceProvider(address: address, serviceName: serviceName)
648 }
649
650 /// Create LiteLLM usage handler
651 access(all) fun createLiteLLMHandler(): @LiteLLMUsageHandler {
652 return <- create LiteLLMUsageHandler()
653 }
654
655 init() {
656 self.VaultStoragePath = /storage/UsageBasedSubscriptionVault
657 self.VaultPublicPath = /public/UsageBasedSubscriptionVault
658 self.ProviderStoragePath = /storage/UsageBasedServiceProvider
659
660 self.totalVaults = 0
661 self.vaultRegistry = {}
662 }
663}