# AiToEarn Rewards Mechanism: Technical Implementation of the Credit-Based System

> Discover AiToEarn's credit-based reward system. Earn credits for tasks, track transactions in MongoDB, and manage automatic expirations. Get paid for your work.

- Repository: [yikart/AiToEarn](https://github.com/yikart/AiToEarn)
- Tags: internals
- Published: 2026-05-12

---

**AiToEarn implements a credit-based reward system where users earn platform credits (stored in cents) upon completing monetization tasks, with all transactions recorded in MongoDB for auditability and automatic expiration handling.**

The AiToEarn platform incentivizes user participation through a sophisticated reward infrastructure built on NestJS and MongoDB. Unlike simple point systems, this implementation treats rewards as monetary credits with full audit trails, expiration management, and transactional safety guarantees.

## Core Architecture of the AiToEarn Rewards Mechanism

### Task Schema and Reward Definitions

Each monetization opportunity begins with the `Task` schema defined in [`project/aitoearn-electron/server/src/db/schema/task.schema.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-electron/server/src/db/schema/task.schema.ts). This schema includes a **`reward: number`** field that stores the monetary value in cents. When a task reaches **`REWARDED`** status, the system creates a corresponding `UserTask` entry containing the reward amount and timestamp (`rewardTime`) in [`project/aitoearn-electron/server/src/modules/task/task.controller.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-electron/server/src/modules/task/task.controller.ts).

### The Credit Ledger Pattern

The platform implements a double-entry style ledger through `CreditsHelperService` located at [`project/aitoearn-backend/libs/helpers/src/credits/credits-helper.service.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-backend/libs/helpers/src/credits/credits-helper.service.ts). This service maintains two critical data structures: the user's aggregate balance and individual **`CreditsRecord`** documents that provide immutable transaction history for every credit movement.

## How Rewards Are Issued and Recorded

### From Task Completion to Credit Balance

When users complete tasks, the flow traverses from [`project/aitoearn-electron/server/src/modules/task/task.controller.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-electron/server/src/modules/task/task.controller.ts) to the credits system. The controller marks tasks as rewarded, triggering the credit issuance workflow that atomically updates the user's balance through the helper service.

### Transaction Safety with @Transactional

All credit modifications use NestJS **`@Transactional`** decorators to ensure ACID compliance across MongoDB operations. If a reward issuance fails midway, the entire operation rolls back, preventing partial credit updates or orphaned `CreditsRecord` documents.

## Managing Credit Lifecycles

### Adding Credits via CreditsHelperService

The **`addCredits()`** method in `CreditsHelperService` handles reward distribution. It accepts an `AddCreditsDto` containing the user ID, amount in cents, credit type (typically `CreditsType.Reward`), description, and metadata for auditing.

```typescript
import { CreditsHelperService } from '@yikart/helpers';
import { AddCreditsDto, CreditsType } from '@yikart/helpers';

async function grantReward(userId: string, amountCents: number) {
  const dto: AddCreditsDto = {
    userId,
    amount: amountCents,
    type: CreditsType.Reward,
    description: 'Task reward',
    metadata: { source: 'task-123' },
  };
  await creditsHelper.addCredits(dto);
}

```

### Deducting Credits for Task Execution

When users execute paid tasks, **`deductCredits()`** validates available balance, checks expiration dates, and decrements the appropriate credit records. This method supports complex scenarios like partial credit consumption from multiple buckets using FIFO (First-In-First-Out) selection logic.

```typescript
import { CreditsHelperService } from '@yikart/helpers';
import { DeductCreditsDto, CreditsType } from '@yikart/helpers';

async function consumeCredits(userId: string, costCents: number) {
  const dto: DeductCreditsDto = {
    userId,
    amount: costCents,
    type: CreditsType.TaskExecution,
    description: 'Start task XYZ',
    metadata: { taskId: 'xyz' },
  };
  await creditsHelper.deductCredits(dto);
}

```

### Automatic Expiration Handling

Credits can include an optional **`expiredAt`** timestamp. A nightly job (`checkUserCreditsExpiration`) scans for expired records, zeros out the balances, and logs separate *expired* records. This prevents stale promotional credits from remaining in circulation while maintaining complete audit trails.

## Frontend Integration

### Displaying Rewards with RewardDisplay

The React frontend consumes reward data through the **`RewardDisplay`** component documented in [`project/aitoearn-web/src/components/README.md`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-web/src/components/README.md). This component intelligently selects the proper pricing model (**CPS**, **CPM**, or **CPE**) and renders the reward amount across three size variants: `sidebar`, `card`, and `compact`.

### Querying User Balances

`CreditsService` at [`project/aitoearn-backend/apps/aitoearn-server/src/core/credits/credits.service.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-backend/apps/aitoearn-server/src/core/credits/credits.service.ts) exposes REST endpoints consumed by the frontend wrapper in [`project/aitoearn-web/src/api/credits.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-web/src/api/credits.ts):

```typescript
import { http } from '@/utils/http';

export function getCreditsBalance() {
  return http.get<{ balance: number }>('user/credits');
}

// Usage
const { balance } = await getCreditsBalance();
console.log(`Current balance: $${(balance / 100).toFixed(2)}`);

```

## Summary

- **Cent-based precision**: AiToEarn stores all rewards as integers (cents) to eliminate floating-point errors common in financial calculations.
- **Double-entry accounting**: Every credit movement generates immutable `CreditsRecord` documents for complete audit trails.
- **Transaction safety**: NestJS `@Transactional` decorators ensure atomic updates across task status and credit balance collections.
- **Expiration management**: Automated nightly jobs handle time-limited credits without manual intervention.
- **Modular separation**: Credit logic (`CreditsHelperService`) remains separate from API exposure (`CreditsService`) and frontend components.

## Frequently Asked Questions

### What currency format does AiToEarn use for rewards?

AiToEarn stores all monetary values as **integers representing cents** (e.g., $1.00 = 100). This approach eliminates floating-point precision errors common in JavaScript financial calculations and simplifies MongoDB aggregation pipelines for reporting.

### How does AiToEarn prevent duplicate reward issuance?

The platform leverages **transactional database operations** using NestJS `@Transactional` decorators. When a task status changes to `REWARDED` in [`task.controller.ts`](https://github.com/yikart/AiToEarn/blob/main/task.controller.ts), the credit creation and task update occur within a single atomic transaction, ensuring either both succeed or both fail, preventing double-payment scenarios.

### Can credits expire in the AiToEarn system?

Yes, the `CreditsHelperService` supports optional expiration through the **`expiredAt`** timestamp field. A scheduled nightly job (`checkUserCreditsExpiration`) scans for expired records, zeros out usable balances, and creates corresponding audit entries to maintain ledger integrity and prevent stale currency usage.

### How does the frontend determine which pricing model to display?

The `RewardDisplay` component automatically selects between **CPS** (Cost Per Sale), **CPM** (Cost Per Mille), and **CPE** (Cost Per Engagement) models based on the task's `pricingModel` property passed from the backend. It renders the reward amount appropriately for three distinct layouts: sidebar navigation, task cards, and compact list views.