This implementation adds oracle functionality to the Utility Drip Contracts, allowing users to pay in XLM while utilities are priced in USD.
The solution consists of two main components:
- Price Oracle Contract - Manages XLM to USD exchange rates
- Enhanced Utility Contract - Integrates with the oracle for price conversion
- Price Management: Stores current XLM to USD exchange rate
- Staleness Protection: Rejects prices older than 5 minutes
- Access Control: Admin and updater roles for secure price updates
- Conversion Functions: Direct XLM↔USD conversion methods
initialize()- Set up oracle with admin, updater, and initial priceupdate_price()- Update exchange rate (authorized only)xlm_to_usd_cents()- Convert XLM amount to USD centsusd_cents_to_xlm()- Convert USD cents to XLM amountget_fresh_price()- Get price with staleness check
- Automatic Conversion: Detects XLM payments and converts to USD
- Provider Withdrawals: Allows providers to withdraw earnings in XLM
- Conversion Events: Emits events for transparency
- Backward Compatibility: Works with existing custom tokens
- Emergency Trust Mode: Enables manual recovery when oracle heartbeat is stale for 72 hours
- Unanimous Governance Guard: Emergency actions require 100% approval from all active members
top_up()- Enhanced to handle XLM→USD conversionwithdraw_earnings()- New function for USD→XLM conversionget_current_rate()- Get current exchange rateis_trust_mode()- Returns true when oracle heartbeat is stale for more than 72 hourspropose_emergency_flow_rate()- Create emergency proposal to set manual flow ratepropose_emergency_pause()- Create emergency proposal to pause a meter cycleapprove_emergency_action()- Approve an emergency proposal (one vote per member)execute_emergency_action()- Execute only after unanimous member approval
- User calls
top_up()with XLM amount - Contract detects native token (XLM)
- Calls oracle to convert XLM→USD cents
- Credits meter account in USD cents
- Emits conversion event
- Provider calls
withdraw_earnings()with USD amount - Contract calls oracle to convert USD→XLM
- Transfers XLM to provider
- Updates meter balance/debt
- Emits conversion event
pub struct PriceData {
pub price: i128, // Price in smallest units (cents for USD)
pub decimals: u32, // Number of decimal places
pub last_updated: u64, // Timestamp of last update
}New error types added:
PriceConversionFailed- Oracle conversion failedInvalidTokenAmount- Zero or negative amountsStalePrice- Oracle price too old (oracle contract)
- Oracle Authorization: Only authorized updater can modify prices
- Staleness Checks: Rejects old price data
- Access Control: Admin controls updater role
- Event Logging: All conversions emit events for transparency
- Trust Mode Gate: Emergency manual controls are blocked while oracle heartbeat is healthy
- Strict Unanimity: Every registered active member must approve emergency actions
- Duplicate Vote Prevention: A member can approve a proposal only once
Trust Mode is derived from on-chain oracle heartbeat state:
- Utility contract fetches oracle
PriceData.last_updated - If
now - last_updated > 72 hours, Trust Mode is active - If no oracle address is configured, Trust Mode is treated as active for recovery operations
Boundary behavior is strict:
- exactly 72 hours stale: not yet in Trust Mode
- greater than 72 hours stale: Trust Mode active
Only in Trust Mode, active members can unanimously approve:
- manual
max_flow_rate_per_hourupdate for a meter - manual cycle pause (
is_paused = true) for a meter
Outside Trust Mode these manual emergency actions revert.
- Members are addresses registered through
register_active_user() - Membership is tracked uniquely per address
- Proposal creator auto-approves their proposal
- Additional approvals are counted once per member
- Execution requires
approval_count == active_member_count
- When oracle heartbeat becomes healthy again, new emergency proposals and approvals are blocked
- Already executed emergency actions remain in state (no automatic rollback)
This keeps fallback narrowly scoped to catastrophic oracle inactivity without weakening normal oracle-driven behavior.
Comprehensive tests included for:
- Oracle initialization and price updates
- XLM to USD conversion in top-ups
- USD to XLM conversion in withdrawals
- Rate retrieval functionality
- Error conditions
- Deploy Price Oracle contract
- Initialize with admin, updater, and initial price
- Deploy Utility Contract (or upgrade existing)
- Set oracle address in Utility Contract
- Set up price updater service for real-time rates
- Native token detection uses address pattern matching
- Custom tokens (starting with "CA") bypass conversion
- All internal accounting remains in USD cents
- Oracle calls include freshness validation
// Update price to $1.75 per XLM (175 cents)
oracle.update_price(175);
// User tops up 100 XLM
utility.top_up(meter_id, 100);
// Internally: 100 XLM * 175 cents = 17500 cents ($175.00)This implementation provides a robust, secure solution for XLM payments while maintaining USD-based utility pricing.