Billing Payment Service - Geryon
The Billing Payment Service is the financial core of the Dante GPU Platform. It manages dGPU token wallets, processes transactions, calculates real-time billing for GPU usage, and integrates with the Solana blockchain for dGPU token operations.
1. Responsibilities
The Billing Payment Service has the following key responsibilities:
Wallet Management: Creates and manages dGPU token wallets for users and providers. Tracks balances (available, locked, pending).
Transaction Processing: Handles various transaction types such as deposits, withdrawals, payments for GPU usage, and provider payouts using the dGPU token (SPL Token address:
7xUV6YR3rZMfExPqZiovQSUxpnHxr2KJJqFg1bFrpump
).Solana Blockchain Integration: Interacts with the Solana blockchain for token operations, including creating Associated Token Accounts (ATAs), transferring tokens, and confirming transactions.
Real-time Billing: Implements session-based billing for GPU rentals, tracking usage with precision (e.g., per minute) and calculating costs in real-time. This includes handling insufficient funds and grace periods.
Dynamic Pricing Engine: Calculates rental costs based on GPU model, VRAM, power consumption, and potentially dynamic factors like demand and supply.
Usage Tracking: Receives and processes usage updates from Provider Daemons for active rental sessions.
Platform Fee Management: Calculates and collects platform fees from transactions (e.g., 5% default).
Provider Payouts: Manages and processes earnings for GPU providers.
Data Persistence: Stores wallet, transaction, session, and billing records in a PostgreSQL database.
API Exposure: Provides HTTP APIs for wallet operations, billing inquiries, pricing, and session management.
Service Discovery: Registers with Consul for discovery by other services.
2. Tech Stack
The Billing Payment Service utilizes the following technologies:
Programming Language:
Go (version 1.21+)
Database:
PostgreSQL
(usingpgxpool
)Blockchain Interaction: Solana (using
gagliardetto/solana-go
library)HTTP Routing: Chi router
Messaging/Event Streaming: NATS JetStream (for receiving usage updates and publishing payment events)
Service Discovery: Consul
Logging: Zap for structured logging
Decimal Arithmetic:
shopspring/decimal
for precise financial calculationsConfiguration: YAML files
3. Core Components and Logic
3.1. Configuration (internal/config/config.go
, configs/config.yaml
)
The service's operation is defined by configs/config.yaml, loaded into config.Config.
Key sections include:
server
: HTTP server settings (port, timeouts).database
: PostgreSQL connection details.solana
: Solana RPC/WS URLs, dGPU token address (7xUV6YR3rZMfExPqZiovQSUxpnHxr2KJJqFg1bFrpump
), platform wallet, and private key path.pricing
: Base rates for GPU models, VRAM/power multipliers, platform fee.nats
: NATS server address and subjects for events.consul
: Consul agent address and service registration details.billing
: Billing cycle parameters (e.g.,billing_interval
,minimum_balance
).
# Snippet from configs/config.yaml
solana:
rpc_url: "https://api.mainnet-beta.solana.com"
ws_url: "wss://api.mainnet-beta.solana.com"
dgpu_token_address: "7xUV6YR3rZMfExPqZiovQSUxpnHxr2KJJqFg1bFrpump"
platform_wallet: "YOUR_PLATFORM_WALLET_ADDRESS"
private_key_path: "/secrets/solana_private_key"
commitment: "confirmed"
timeout: "30s"
max_retries: 3
pricing:
base_rates:
"nvidia-geforce-rtx-4090": 0.50
# ... other GPU models
"default": 0.25
vram_rate_per_gb: 0.02
power_multiplier: 0.001
platform_fee_percent: 5.0
minimum_session_minutes: 1
maximum_session_hours: 24
3.2. Data Models (internal/models/
)
Wallet
: Represents a user, provider, or platform dGPU token wallet, including balances (total, locked, available).// Snippet from internal/models/wallet.go type Wallet struct { ID uuid.UUID `json:"id" db:"id"` UserID string `json:"user_id" db:"user_id"` WalletType WalletType `json:"wallet_type" db:"wallet_type"` SolanaAddress string `json:"solana_address" db:"solana_address"` Balance decimal.Decimal `json:"balance" db:"balance"` LockedBalance decimal.Decimal `json:"locked_balance" db:"locked_balance"` PendingBalance decimal.Decimal `json:"pending_balance" db:"pending_balance"` IsActive bool `json:"is_active" db:"is_active"` // ... other fields like CreatedAt, UpdatedAt } func (w *Wallet) AvailableBalance() decimal.Decimal { return w.Balance.Sub(w.LockedBalance) }
Transaction
: Records all token movements, including type (deposit, payment, payout), status, amount, fees, and Solana signature.RentalSession
: Tracks an active or completed GPU rental, including allocated resources, pricing rates, duration, and total costs.// Snippet from internal/models/billing.go type RentalSession struct { ID uuid.UUID `json:"id" db:"id"` UserID string `json:"user_id" db:"user_id"` ProviderID uuid.UUID `json:"provider_id" db:"provider_id"` // ... many other fields for GPU details, pricing, timing, costs ... Status SessionStatus `json:"status" db:"status"` HourlyRate decimal.Decimal `json:"hourly_rate" db:"hourly_rate"` TotalCost decimal.Decimal `json:"total_cost" db:"total_cost"` StartedAt time.Time `json:"started_at" db:"started_at"` EndedAt *time.Time `json:"ended_at,omitempty" db:"ended_at"` LastBilledAt time.Time `json:"last_billed_at" db:"last_billed_at"` }
UsageRecord
: Stores periodic usage metrics for a session (GPU utilization, power draw) and the cost for that period.BillingRecord
: Aggregated billing information for a completed session or billing cycle.Custom error types (e.g.,
ErrWalletNotFound
,ErrInsufficientFunds
,ErrSolanaTransaction
) and structuredBillingError
are defined ininternal/models/errors.go
.
3.3. Database Store (internal/store/
)
PostgresStore
: Implements data persistence using PostgreSQL.Schema Initialization (
schema.go
,Initialize
method): Defines and creates tables for wallets, transactions, rental sessions, usage records, billing records, and provider rates if they don't exist.// Snippet from internal/store/schema.go - Wallets Table const createWalletsTable = ` CREATE TABLE IF NOT EXISTS wallets ( id UUID PRIMARY KEY, user_id VARCHAR(255) NOT NULL, wallet_type VARCHAR(50) NOT NULL CHECK (wallet_type IN ('user', 'provider', 'platform')), solana_address VARCHAR(255) NOT NULL, balance DECIMAL(20,9) NOT NULL DEFAULT 0, locked_balance DECIMAL(20,9) NOT NULL DEFAULT 0, pending_balance DECIMAL(20,9) NOT NULL DEFAULT 0, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_activity_at TIMESTAMPTZ, UNIQUE(user_id, wallet_type), UNIQUE(solana_address) ); `
Provides CRUD operations for all data models (e.g.,
CreateWallet
,GetRentalSession
,UpdateTransactionStatus
).
3.4. Solana Client (internal/solana/client.go
)
Client
: Manages interactions with the Solana blockchain.Initialization: Connects to Solana RPC and WebSocket endpoints, loads the platform's private key.
GetTokenBalance
: Fetches the dGPU token balance for a given Solana wallet address by querying its Associated Token Account (ATA).TransferTokens
: Creates and sends a Solana transaction to transfer dGPU tokens between ATAs, signed by the platform's private key (or user's key for withdrawals).ConfirmTransaction
: Polls the blockchain to confirm transaction finality.CreateAssociatedTokenAccount
: Creates an ATA for a user if one doesn't exist for the dGPU token.
3.5. Pricing Engine (internal/pricing/engine.go
)
Engine
: Calculates GPU rental costs.Configuration: Loads base rates for different GPU models, VRAM/power cost factors, and platform fee percentage from
config.Pricing
.CalculatePricing
: Computes the total hourly rate and total cost for a rental based on GPU model, VRAM, estimated power, duration, and dynamic factors (demand/supply multipliers - currently placeholders).// Snippet from internal/pricing/engine.go - CalculatePricing method func (e *Engine) CalculatePricing(ctx context.Context, req *PricingRequest) (*PricingResponse, error) { // ... (get baseRate, calculate vramHourlyRate, powerHourlyRate) ... demandMultiplier, supplyBonus, _ := e.getDynamicPricingFactors(ctx, req) // Dynamic factors adjustedBaseRate := baseRate.Mul(demandMultiplier).Sub(baseRate.Mul(supplyBonus)) // ... (ensure adjustedBaseRate isn't too low) ... totalHourlyRate := adjustedBaseRate.Add(vramHourlyRate).Add(powerHourlyRate) baseCost := adjustedBaseRate.Mul(req.DurationHours) vramCost := vramHourlyRate.Mul(req.DurationHours) powerCost := powerHourlyRate.Mul(req.DurationHours) subtotalCost := baseCost.Add(vramCost).Add(powerCost) platformFee := subtotalCost.Mul(e.config.PlatformFeePercent).Div(decimal.NewFromInt(100)) totalCost := subtotalCost.Add(platformFee) providerEarnings := subtotalCost.Sub(platformFee) // Corrected from subtotalCost.Sub(platformFee) // ... (return PricingResponse) ... return &PricingResponse{ // ... TotalHourlyRate: totalHourlyRate, TotalCost: totalCost, PlatformFee: platformFee, ProviderEarnings: providerEarnings, // This was an example correction // ... }, nil }
3.6. Billing Service Logic (internal/service/billing.go
)
BillingService
: Orchestrates wallet management, session handling, usage processing, and payment/payout operations.StartRentalSession
:Validates user balance against minimum requirements and estimated cost for an initial period (e.g., 1 hour).
Locks funds in the user's wallet.
Creates a
RentalSession
record in the database.
ProcessUsageUpdate
:Receives real-time usage metrics from a Provider Daemon.
Calculates the cost for the reported period using the session's established rates.
Creates a
UsageRecord
.Updates the
RentalSession
with the latestActualPowerW
and accumulatedTotalCost
.
EndRentalSession
:Calculates the final session cost.
Updates the session status to
completed
and records final costs.Unlocks any remaining funds and deducts the final cost from the user's wallet.
(Future: Initiates provider payout transaction).
ProcessDeposit
/ProcessWithdrawal
: Handles dGPU token deposits and withdrawals, involving Solana transaction confirmation and database updates.
3.7. HTTP Handlers (internal/handlers/
)
Wallet Handlers (
wallet.go
): Expose endpoints for wallet creation, balance checks, deposits, and withdrawals.Billing Handlers (
billing.go
): Expose endpoints for starting/ending rental sessions, processing usage updates, getting current usage, billing history, pricing calculations, and provider earnings/payouts.// Snippet from internal/handlers/billing.go - StartRentalSession handler func StartRentalSession(billingService *service.BillingService, logger *zap.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req models.SessionStartRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { // ... error handling ... writeErrorResponse(w, http.StatusBadRequest, "Invalid request body", err) return } session, err := billingService.StartRentalSession(r.Context(), &req) if err != nil { // ... error handling ... writeErrorResponse(w, http.StatusInternalServerError, "Failed to start rental session", err) return } writeJSONResponse(w, http.StatusCreated, session) } }
3.8. Main Application (cmd/main.go
)
Initializes configuration, logger, database connection, Solana client, pricing engine, and the main billing service.
Sets up the Chi HTTP router with middleware (RequestID, RealIP, Logger, Recoverer, Timeout, CORS).
Registers API routes and handlers.
Handles graceful shutdown.
(Consul registration is defined in
Config
but its direct use incmd/main.go
is not shown in provided snippets, though implied by config structure).
4. API Endpoints
The service exposes various endpoints under /api/v1/
.
Wallet Management:
POST /wallet
: Create a new wallet.GET /wallet/{walletID}/balance
: Get wallet balance.POST /wallet/{walletID}/deposit
: Process token deposit.POST /wallet/{walletID}/withdraw
: Process token withdrawal.GET /wallet/{walletID}/transactions
: Get transaction history.
Billing & Sessions:
POST /billing/start-session
: Start a GPU rental session.POST /billing/end-session
: End a GPU rental session.POST /billing/usage-update
: Process real-time usage updates.GET /billing/current-usage/{sessionID}
: Get current usage and cost for an active session.GET /billing/history
: Get billing history (supports filtering).
Pricing:
POST /pricing/calculate
: Calculate estimated pricing for given requirements.GET /pricing/rates
: Get current base pricing rates.
Provider Operations:
GET /provider/{providerID}/earnings
: Get provider earnings summary.POST /provider/{providerID}/payout
: Request a payout for a provider.GET /provider/{providerID}/rates
: Get provider-specific rates.PUT /provider/{providerID}/rates
: Set provider-specific rates.
Health Check:
GET /health
: Basic health check for the service.
5. Workflow Examples
5.1. Starting a Rental Session
Client (Scheduler or API Gateway) calls
POST /api/v1/billing/start-session
with user, provider, job, and resource details.BillingService.StartRentalSession
:Retrieves the user's wallet.
Checks if available balance meets minimum requirements.
Uses
PricingEngine.CalculatePricing
to determine the hourly rate.Locks funds in the user's wallet for an initial period (e.g., 1 hour).
Updates the user's wallet in the database (
PostgresStore.UpdateWalletBalance
).Creates a new
RentalSession
record (PostgresStore.CreateRentalSession
).Creates a
Transaction
record for the fund lock.Returns session details, including estimated runtime based on available balance.
5.2. Processing Usage Updates
Provider Daemon sends a usage update (GPU utilization, power draw) via NATS or HTTP to
POST /api/v1/billing/usage-update
.BillingService.ProcessUsageUpdate
:Retrieves the active
RentalSession
.Calculates the cost for the usage period based on the session's established rates.
Creates a
UsageRecord
in the database.Updates the
RentalSession
with the accumulated cost and latest actual power draw.(Periodically, or on session end, the service would deduct the accrued cost from locked funds and potentially transfer to provider/platform wallets).
5.3. Token Deposit
User deposits dGPU tokens to their designated Solana address associated with their Dante platform wallet.
An external process or the user notifies the platform of the deposit via
POST /api/v1/wallet/{walletID}/deposit
with the Solana transaction signature.BillingService.ProcessDeposit
:Uses
SolanaClient.ConfirmTransaction
to verify the transaction on the Solana blockchain.Retrieves the user's wallet.
Updates the wallet balance in the database (
wallet.AddFunds
,store.UpdateWalletBalance
).Creates a
Transaction
record for the deposit and marks it as confirmed.
6. Future Considerations
Automated Payouts: Implement scheduled or event-driven payouts to providers.
Dispute Resolution: Mechanisms for handling billing disputes.
Advanced Dynamic Pricing: Incorporate real-time market data, provider reputation, and other factors into the pricing engine.
Subscription Models: Introduce subscription plans or pre-paid packages.
Fiat On-Ramp/Off-Ramp: Integration with services to convert fiat currency to/from dGPU tokens.
Enhanced Security: Multi-signature wallets for platform funds, more robust fraud detection.
NATS Eventing: Publish more granular events for session status changes, billing cycles, and payment confirmations.
Tax Calculation: Integration for calculating and reporting taxes on transactions if applicable.
Last updated