Smart Contract

SimpleUsageSubscriptions

A.6daee039a7b9c2f0.SimpleUsageSubscriptions

Valid From

123,196,379

Deployed

6d ago
Feb 21, 2026, 10:01:28 PM UTC

Dependents

7 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import FlareFDCTriggers from 0x6daee039a7b9c2f0
4
5/// SimpleUsageSubscriptions: Simplified usage-based billing for LiteLLM
6/// Users connect to this contract to create vaults and grant payment entitlements
7access(all) contract SimpleUsageSubscriptions {
8    
9    /// Events
10    access(all) event SubscriptionCreated(vaultId: UInt64, customer: Address, provider: Address)
11    access(all) event UsageUpdated(vaultId: UInt64, newPrice: UFix64, tier: String)
12    access(all) event PaymentProcessed(vaultId: UInt64, amount: UFix64)
13    
14    /// Storage paths
15    access(all) let VaultStoragePath: StoragePath
16    access(all) let VaultPublicPath: PublicPath
17    
18    /// Global state
19    access(all) var totalVaults: UInt64
20    
21    /// Pricing tiers
22    access(all) struct PricingTier {
23        access(all) let name: String
24        access(all) let minTokens: UInt64
25        access(all) let pricePerK: UFix64
26        access(all) let discount: UFix64
27        
28        init(name: String, minTokens: UInt64, pricePerK: UFix64, discount: UFix64) {
29            self.name = name
30            self.minTokens = minTokens
31            self.pricePerK = pricePerK
32            self.discount = discount
33        }
34    }
35    
36    /// Usage report from LiteLLM
37    access(all) struct UsageReport {
38        access(all) let vaultId: UInt64
39        access(all) let totalTokens: UInt64
40        access(all) let apiCalls: UInt64
41        access(all) let gpt4Tokens: UInt64
42        access(all) let gpt35Tokens: UInt64
43        access(all) let timestamp: UFix64
44        
45        init(vaultId: UInt64, totalTokens: UInt64, apiCalls: UInt64, gpt4Tokens: UInt64, gpt35Tokens: UInt64) {
46            self.vaultId = vaultId
47            self.totalTokens = totalTokens
48            self.apiCalls = apiCalls
49            self.gpt4Tokens = gpt4Tokens
50            self.gpt35Tokens = gpt35Tokens
51            self.timestamp = getCurrentBlock().timestamp
52        }
53    }
54    
55    /// Subscription vault with usage-based pricing
56    access(all) resource SubscriptionVault {
57        access(all) let id: UInt64
58        access(all) let customer: Address
59        access(all) let provider: Address
60        access(self) let vault: @{FungibleToken.Vault}
61        
62        // Usage tracking
63        access(all) var lastUsage: UsageReport?
64        access(all) var currentTier: PricingTier
65        access(all) var currentPrice: UFix64
66        access(all) var allowedWithdrawal: UFix64
67        
68        /// Process usage update from LiteLLM via FDC
69        access(all) fun updateUsage(_ usage: UsageReport) {
70            self.lastUsage = usage
71            
72            // Calculate tier
73            self.currentTier = SimpleUsageSubscriptions.getTierForUsage(usage.totalTokens)
74            
75            // Calculate price
76            let basePrice = UFix64(usage.totalTokens) / 1000.0 * self.currentTier.pricePerK
77            let discounted = basePrice * (1.0 - self.currentTier.discount)
78            
79            // Model multipliers
80            let gpt4Cost = UFix64(usage.gpt4Tokens) / 1000.0 * self.currentTier.pricePerK * 1.5
81            let gpt35Cost = UFix64(usage.gpt35Tokens) / 1000.0 * self.currentTier.pricePerK * 0.8
82            
83            self.currentPrice = gpt4Cost + gpt35Cost
84            self.allowedWithdrawal = self.currentPrice
85            
86            emit UsageUpdated(
87                vaultId: self.id,
88                newPrice: self.currentPrice,
89                tier: self.currentTier.name
90            )
91        }
92        
93        /// Provider withdraws based on usage
94        access(all) fun withdrawByUsage(amount: UFix64): @{FungibleToken.Vault} {
95            pre {
96                amount <= self.allowedWithdrawal: "Exceeds usage allowance"
97                amount <= self.vault.balance: "Insufficient balance"
98            }
99            
100            self.allowedWithdrawal = self.allowedWithdrawal - amount
101            let payment <- self.vault.withdraw(amount: amount)
102            
103            emit PaymentProcessed(vaultId: self.id, amount: amount)
104            return <- payment
105        }
106        
107        /// Customer deposits funds
108        access(all) fun deposit(from: @{FungibleToken.Vault}) {
109            self.vault.deposit(from: <- from)
110        }
111        
112        /// Get vault info
113        access(all) fun getInfo(): {String: AnyStruct} {
114            return {
115                "balance": self.vault.balance,
116                "currentPrice": self.currentPrice,
117                "allowedWithdrawal": self.allowedWithdrawal,
118                "tier": self.currentTier.name,
119                "lastUpdate": self.lastUsage?.timestamp ?? 0.0
120            }
121        }
122        
123        init(customer: Address, provider: Address, initialDeposit: @{FungibleToken.Vault}) {
124            self.id = SimpleUsageSubscriptions.totalVaults
125            SimpleUsageSubscriptions.totalVaults = SimpleUsageSubscriptions.totalVaults + 1
126            
127            self.customer = customer
128            self.provider = provider
129            self.vault <- initialDeposit
130            
131            self.lastUsage = nil
132            self.currentTier = SimpleUsageSubscriptions.getStarterTier()
133            self.currentPrice = 0.0
134            self.allowedWithdrawal = 0.0
135        }
136    }
137    
138    /// FDC Handler for LiteLLM usage updates
139    access(all) resource LiteLLMHandler: FlareFDCTriggers.TriggerHandler {
140        access(self) var active: Bool
141        
142        access(all) fun handleTrigger(trigger: FlareFDCTriggers.FDCTrigger): Bool {
143            // Extract usage data from FDC payload
144            if let vaultIdAny = trigger.payload["vaultId"] {
145                if let vaultId = vaultIdAny as? UInt64 {
146                    let usage = UsageReport(
147                        vaultId: vaultId,
148                        totalTokens: trigger.payload["totalTokens"] as? UInt64 ?? 0,
149                        apiCalls: trigger.payload["apiCalls"] as? UInt64 ?? 0,
150                        gpt4Tokens: trigger.payload["gpt4Tokens"] as? UInt64 ?? 0,
151                        gpt35Tokens: trigger.payload["gpt35Tokens"] as? UInt64 ?? 0
152                    )
153                    
154                    // This would update the vault in production
155                    // For demo, just emit the event
156                    emit UsageUpdated(
157                        vaultId: vaultId,
158                        newPrice: UFix64(usage.totalTokens) / 1000.0 * 0.02,
159                        tier: "Auto-calculated"
160                    )
161                    
162                    return true
163                }
164            }
165            return false
166        }
167        
168        access(all) fun getSupportedTriggerTypes(): [FlareFDCTriggers.TriggerType] {
169            return [FlareFDCTriggers.TriggerType.DefiProtocolEvent]
170        }
171        
172        access(all) fun isActive(): Bool {
173            return self.active
174        }
175        
176        init() {
177            self.active = true
178        }
179    }
180    
181    /// Public functions users connect to
182    
183    /// Create subscription vault (main user entry point)
184    access(all) fun createSubscriptionVault(
185        customer: Address,
186        provider: Address,
187        initialDeposit: @{FungibleToken.Vault}
188    ): @SubscriptionVault {
189        let vault <- create SubscriptionVault(
190            customer: customer,
191            provider: provider,
192            initialDeposit: <- initialDeposit
193        )
194        
195        emit SubscriptionCreated(
196            vaultId: vault.id,
197            customer: customer,
198            provider: provider
199        )
200        
201        return <- vault
202    }
203    
204    /// Process usage update (called by FDC)
205    access(all) fun processUsageUpdate(usage: UsageReport) {
206        emit UsageUpdated(
207            vaultId: usage.vaultId,
208            newPrice: UFix64(usage.totalTokens) / 1000.0 * 0.02,
209            tier: self.getTierForUsage(usage.totalTokens).name
210        )
211    }
212    
213    /// Get pricing tier for usage amount
214    access(all) fun getTierForUsage(_ tokens: UInt64): PricingTier {
215        if tokens >= 10000000 {
216            return PricingTier(name: "Enterprise", minTokens: 10000000, pricePerK: 0.008, discount: 0.3)
217        } else if tokens >= 1000000 {
218            return PricingTier(name: "Scale", minTokens: 1000000, pricePerK: 0.01, discount: 0.2)
219        } else if tokens >= 100000 {
220            return PricingTier(name: "Growth", minTokens: 100000, pricePerK: 0.015, discount: 0.1)
221        } else {
222            return self.getStarterTier()
223        }
224    }
225    
226    access(all) fun getStarterTier(): PricingTier {
227        return PricingTier(name: "Starter", minTokens: 0, pricePerK: 0.02, discount: 0.0)
228    }
229    
230    /// Create LiteLLM handler
231    access(all) fun createLiteLLMHandler(): @LiteLLMHandler {
232        return <- create LiteLLMHandler()
233    }
234    
235    init() {
236        self.VaultStoragePath = /storage/SimpleUsageSubscriptionVault
237        self.VaultPublicPath = /public/SimpleUsageSubscriptionVault
238        self.totalVaults = 0
239    }
240}