Subscriptions.sol
Overview
The Subscriptions.sol contract provides two payment models for continuous AI agent services on Nexis: epoch-based subscriptions (periodic fixed payments) and rate-based streams (continuous per-second payments). This dual-model approach supports both traditional subscription patterns and novel streaming payment use cases. Contract Location:/nexis-appchain/packages/contracts-bedrock/contracts/Subscriptions.sol
Key Features
- Epoch Subscriptions: Fixed amount payments at regular intervals (daily, weekly, monthly)
- Payment Streams: Continuous per-second payment flows with on-demand withdrawals
- Multi-Asset Support: ETH and ERC20 token payments
- Prefunding: Optional upfront funding for multiple periods
- Flexible Cancellation: Cancel anytime with automatic refunds
- Agent Integration: Direct payments to agent owners via Agents.sol
Architecture
Payment Models Comparison
| Feature | Epoch Subscriptions | Rate-Based Streams |
|---|---|---|
| Payment Frequency | Fixed intervals (1 day, 1 week, 1 month) | Continuous (per second) |
| Processing | Manual processSubscription() call | Automatic accrual, manual withdrawal |
| Typical Use Case | Monthly API access, tier-based services | Pay-per-use, metered billing, real-time services |
| Prefunding | Multiple epochs upfront | Full duration upfront |
| Withdrawal | Automatic on processing | Agent withdraws accrued amount anytime |
| Cancellation | Refund unused balance | Refund unstreamed portion |
| Gas Efficiency | Lower (batch processing) | Higher (continuous calculation) |
Core Data Structures
Subscription
Stream
Contract Roles
| Role | Bytes32 Identifier | Description |
|---|---|---|
DEFAULT_ADMIN_ROLE | 0x00 | Administrative control, can cancel subscriptions/streams |
PAUSER_ROLE | keccak256("PAUSER_ROLE") | Emergency pause capability |
Epoch-Based Subscriptions
createSubscription
Create a new epoch-based subscription to an agent.| Parameter | Type | Description |
|---|---|---|
agentId | uint256 | Agent to subscribe to |
asset | address | Payment asset (address(0) for ETH) |
amountPerEpoch | uint256 | Payment amount per epoch |
epochDuration | uint64 | Epoch duration in seconds (e.g., 86400 = 1 day) |
prefundEpochs | uint8 | Number of epochs to prepay (0-255) |
metadataURI | string | Subscription details (service tier, features, etc.) |
subscriptionId - Unique subscription identifier
Payment:
- For ETH:
msg.valuemust equalamountPerEpoch × prefundEpochs - For ERC20: Caller must approve contract to spend
amountPerEpoch × prefundEpochs
SubscriptionCreated(...)SubscriptionFunded(...)(if prefunded)
fundSubscription
Add funds to an existing subscription.subscriptionId: Subscription IDepochs: Number of epochs to fund
- Subscription must be active
SubscriptionFunded(uint256 indexed subscriptionId, uint256 amount, address indexed funder)
Example:
processSubscription
Process a subscription payment (can be called by anyone).- Subscription is active
- Current time >=
nextCharge - Balance >=
amountPerEpoch
- Deducts
amountPerEpochfrom balance - Increments
nextChargebyepochDuration - Transfers payment to agent owner
- Emits
SubscriptionProcessed
SubscriptionProcessed(uint256 indexed subscriptionId, address indexed recipient, uint256 amount, uint64 nextCharge)
Example (Manual Processing):
cancelSubscription
Cancel a subscription and refund remaining balance.DEFAULT_ADMIN_ROLE
Behavior:
- Sets subscription to inactive
- Refunds remaining balance to payer
SubscriptionCancelled(uint256 indexed subscriptionId, address indexed payer, uint256 refundedAmount)
Example:
getSubscription
Query subscription details.Rate-Based Payment Streams
createStream
Create a continuous payment stream to an agent.| Parameter | Type | Description |
|---|---|---|
agentId | uint256 | Agent receiving stream |
asset | address | Payment asset |
totalAmount | uint256 | Total stream amount |
start | uint64 | Stream start timestamp |
end | uint64 | Stream end timestamp |
integrationURI | string | Integration details, API keys, etc. |
totalAmount % (end - start) == 0(evenly divisible rate)end > start
- Full
totalAmountmust be provided upfront
StreamCreated(...)
Example (7-Day Stream):
withdrawFromStream
Withdraw accrued stream payments (agent owner only).- Calculates withdrawable amount based on elapsed time
- Transfers to agent owner
- Updates
withdrawnamount
StreamWithdrawn(uint256 indexed streamId, address indexed recipient, uint256 amount)
Example:
cancelStream
Cancel a stream and refund unstreamed portion.DEFAULT_ADMIN_ROLE
Behavior:
- Calculates and transfers any withdrawable amount to agent owner
- Calculates unstreamed amount
- Refunds unstreamed amount to payer
- Sets stream inactive
StreamWithdrawn(...)(if withdrawable > 0)StreamCancelled(uint256 indexed streamId, address indexed payer, uint256 refundedAmount)
getStream
Query stream details.Events Reference
Subscription Events
Stream Events
Use Cases & Examples
Use Case 1: SaaS API Subscription
Use Case 2: Pay-Per-Inference (Streaming)
Use Case 3: Tiered Subscription with Auto-Renewal
Use Case 4: Escrow with Time-Release
Admin Functions
pause / unpause
Emergency pause contract operations.setAgents
Update Agents.sol contract reference.Integration Patterns
Subscription Dashboard
Stream Dashboard
Security Considerations
Reentrancy Protection
All state-changing functions with transfers usenonReentrant modifier.
Rate Calculation
- Stream rates must divide evenly (
totalAmount % duration == 0) - Prevents rounding errors and dust amounts
Authorization
- Only agent owners can withdraw from streams
- Only payers (or admin) can cancel subscriptions/streams
Time Manipulation
- Uses
block.timestampfor time calculations - Miners can manipulate up to ~15 seconds
- Not critical for hourly/daily payments
Gas Optimization
- Subscription Processing: Use bots to batch-process multiple subscriptions
- Stream Withdrawals: Agents should withdraw periodically (e.g., weekly) rather than frequently
- Prefunding: Pay for multiple epochs upfront to reduce transaction costs
Related Contracts
- Agents.sol - Validates agent existence and retrieves owner addresses
- Tasks.sol - Alternative one-time payment model
- Treasury.sol - Could integrate for protocol fees on subscriptions
ABI & Deployment
ABI Location:/nexis-appchain/packages/contracts-bedrock/artifacts/contracts/Subscriptions.sol/Subscriptions.json
Network Addresses:
| Network | Contract Address | Explorer |
|---|---|---|
| Nexis Mainnet | 0x... | View Contract |
| Nexis Testnet | 0x... | View Contract |
Support & Resources
- GitHub: nexis-network/nexis-appchain
- Discord: Nexis Community
- Documentation: nex-t1.ai