Feature: Decentralized Payments (Starknet)
Relevant source files
The following files were used as context for generating this wiki page:
- apps/backend/src/payment/payment.service.ts
- apps/backend/src/starknet/starknet.service.ts
- ARCHITECTURE.md
- README.md
- apps/dojo/README.md
- apps/backend/src/users/guards/startnet.auth.guard.ts
- apps/backend/src/payment/entities/payment-transaction.entity.ts
- apps/backend/src/payment/entities/scheduled-payment.entity.ts
- apps/backend/src/payment/entities/payment-limit.entity.ts
- apps/backend/src/payment/entities/webhook-config.entity.ts
The Decentralized Payments feature integrates the OnChain Sage platform with the Starknet network, utilizing STRK tokens to manage payments for premium features, gas fees, and other on-chain interactions. This system is designed to be robust, offering features like deposits, batch payments, scheduled recurring payments, refunds, and configurable webhooks for transaction monitoring.
The backend, built with NestJS, orchestrates all payment-related logic through a dedicated PaymentService. This service communicates with the Starknet blockchain via a StarknetService, which acts as an abstraction layer for smart contract interactions. All transactions are recorded in a PostgreSQL database for history, analytics, and auditing purposes.
Sources: README.md, ARCHITECTURE.md, apps/backend/src/payment/payment.service.ts
System Architecture
The payment system is composed of three main layers: the NestJS Backend, the Starknet Blockchain, and the PostgreSQL Database. The backend's PaymentService handles business logic and exposes API endpoints, the StarknetService interacts with the on-chain contracts, and the database persists all transaction data.
This diagram illustrates the high-level architecture of the payment system.
Core Components
Backend: PaymentService
Located in apps/backend/src/payment/payment.service.ts, the PaymentService is the central component for all payment-related operations. It orchestrates calls to the StarknetService, manages database records, and implements complex features like scheduled payments and webhooks.
Key Methods
| Method | Description |
|---|---|
deposit(walletAddress, amount) | Processes a deposit by calling the StarknetService and recording the transaction. |
upgradeTier(walletAddress) | Handles a user's subscription tier upgrade on-chain. |
payForCall(walletAddress, amount) | Processes a one-time fee payment for a specific action, like a forum call. |
getTransactionStatus(txHash) | Retrieves the status of a transaction from Starknet and updates the local database. |
registerWebhook(webhookConfig) | Saves a webhook configuration to the database and starts monitoring the associated transaction. |
processBatchPayment(batchPaymentDto) | Executes multiple transfers as a single on-chain transaction. |
processRefund(refundDto) | Initiates a refund for a previously confirmed transaction. |
schedulePayment(schedulePaymentDto) | Creates a record for a future or recurring payment. |
setPaymentLimits(paymentLimitDto) | Sets or updates daily and per-transaction limits for a user. |
getPaymentHistory(queryDto) | Retrieves a paginated history of a user's transactions. |
getPaymentAnalytics(queryDto) | Aggregates transaction data for analytical reporting. |
Sources: apps/backend/src/payment/payment.service.ts:71-815
The following diagram shows the sequence of a standard deposit transaction.
Backend: StarknetService
This service, defined in apps/backend/src/starknet/starknet.service.ts, acts as the sole bridge between the backend application and the Starknet network. It initializes the Starknet provider and contract instances using configuration from environment variables. It abstracts away the direct contract call logic, providing simple methods for the PaymentService to use.
The service contains mock implementations for payment functions, indicating that the on-chain contract logic is either under development or defined elsewhere. The methods include deposit, upgradeTier, payForCall, transfer, and batchTransfer.
Sources: apps/backend/src/starknet/starknet.service.ts:18-193, apps/backend/src/starknet/providers/starknet-provider.service.ts:13-79
On-Chain Layer (Dojo/Cairo)
The on-chain components are built using the Dojo framework and Cairo language. While the payment-specific contracts are not detailed, the architecture outlines a system for managing trading signals, staking, and reputation. The payment system leverages this Starknet integration to handle STRK token transactions for gas fees and premium service access. The Dojo configuration files specify world details and writer permissions for development, testnet, and production environments.
Sources: ARCHITECTURE.md, README.md, apps/dojo/README.md, apps/dojo/dojo_dev.toml, apps/dojo/dojo_release.toml
Key Features & Logic
Scheduled & Recurring Payments
The system supports scheduling future and recurring payments using a cron job. The PaymentService includes a method decorated with @Cron('0 * * * * *'), which runs every minute to check for due payments.
// File: apps/backend/src/payment/payment.service.ts:1094-1096
@Cron('0 * * * * *')
async processScheduledPayments() {
// ...
}
When a due payment is found, the service checks limits, executes the transfer via StarknetService, and updates the ScheduledPayment entity. For recurring payments, it calculates the nextExecutionDate based on the defined period (day, week, month, year) until the recurrenceCount is met.
This flowchart shows the logic for processing scheduled payments.
Transaction Webhooks
To provide asynchronous updates on transaction statuses, the system allows clients to register a webhook. A client provides a transactionHash, a callbackUrl, and an optional secretKey. The PaymentService then polls the StarknetService for the transaction status. Once the transaction is confirmed (ACCEPTED_ON_L2 or ACCEPTED_ON_L1), a POST request is sent to the callbackUrl. If a secretKey was provided, the request includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the payload for verification.
Sources: apps/backend/src/payment/payment.service.ts:244-272, 817-919
Payment Limits
The system can enforce spending limits on a per-user basis. The PaymentLimit entity stores a dailyLimit and a transactionMaximum for a given walletAddress. Before processing transactions like deposits or batch payments, the checkTransactionLimits method validates the transaction amount against these limits, throwing a BadRequestException if a limit is exceeded.
Sources: apps/backend/src/payment/payment.service.ts:1016-1064, apps/backend/src/payment/entities/payment-limit.entity.ts
Database Schema
The payment system uses several TypeORM entities to persist data in a PostgreSQL database. The main entities are PaymentTransaction, ScheduledPayment, PaymentLimit, and WebhookConfig.
This ER diagram shows the relationships between the core payment entities.
Sources: apps/backend/src/payment/payment.service.ts:31-38, apps/backend/src/payment/entities/payment-transaction.entity.ts, apps/backend/src/payment/entities/scheduled-payment.entity.ts, apps/backend/src/payment/entities/payment-limit.entity.ts, apps/backend/src/payment/entities/webhook-config.entity.ts
PaymentTransaction Entity
This entity logs every payment transaction initiated through the system.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Primary key. |
transactionHash | string | The on-chain transaction hash. |
senderAddress | string | The Starknet address of the sender. |
recipientAddress | string | The Starknet address of the recipient. |
amount | number | The transaction amount in STRK. |
type | enum | Type of transaction (e.g., DEPOSIT, TRANSFER, REFUND). |
status | enum | Status of the transaction (e.g., PENDING, CONFIRMED, FAILED). |
reference | string | An optional reference or memo for the transaction. |
batchId | string | A UUID to group transactions belonging to the same batch payment. |
timestamp | Date | The timestamp when the record was created. |
Sources: apps/backend/src/payment/entities/payment-transaction.entity.ts
ScheduledPayment Entity
This entity stores information for payments that are to be executed in the future or on a recurring basis.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Primary key. |
senderAddress | string | The Starknet address of the sender. |
recipientAddress | string | The Starknet address of the recipient. |
amount | number | The transaction amount. |
scheduledDate | Date | The initial date and time for the payment execution. |
recurring | boolean | Flag indicating if the payment is recurring. |
recurrencePeriod | enum | The period for recurrence (day, week, month, year). |
recurrenceCount | number | The total number of times the payment should recur. |
status | enum | Status of the schedule (PENDING, EXECUTED, CANCELLED, FAILED). |
nextExecutionDate | Date | The next scheduled time for execution. |
Sources: apps/backend/src/payment/entities/scheduled-payment.entity.ts
Conclusion
The Decentralized Payments feature is a comprehensive system for managing STRK token transactions on the Starknet network. By combining a flexible NestJS backend with on-chain smart contracts, it provides a wide range of functionalities from simple deposits to complex recurring payments and batch processing. The inclusion of webhooks, payment limits, and detailed transaction logging makes it a robust and auditable solution for enabling premium, paid features within the OnChain Sage ecosystem.
Sources: apps/backend/src/payment/payment.service.ts, ARCHITECTURE.md