zfhassaan/laravel-wallet

Ledger-based e-wallet system for Laravel with secure wallet creation, atomic transfers, immutable transactions, and audit-friendly balance calculation. Built for fintech, SaaS platforms, and marketplaces requiring safe, extensible digital wallet infrastructure.

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/zfhassaan/laravel-wallet

dev-master 2026-01-27 10:31 UTC

This package is auto-updated.

Last update: 2026-01-27 10:47:00 UTC


README

A powerful, ledger-based e-wallet system for Laravel applications. Built with security, auditability, and extensibility in mind.

Latest Version Total Downloads License

Features

  • Ledger-Based Architecture: Balance is calculated from immutable transaction records, not stored in a mutable column
  • Tamper Detection: Automatic wallet integrity verification with balance hash validation
  • Atomic Transfers: Guaranteed consistency with database transactions and row-level locking
  • Security First: Password protection, rate limiting, wallet freezing, and comprehensive validation
  • Audit Trail: Complete transaction history with UUIDs, references, and metadata
  • QR Payments: Generate and process secure QR code payments for instant wallet-to-wallet transactions
  • Conversion Rates: Flexible conversion rate system (1:1, 10:1, 100:1, etc.) for different currency representations
  • Production Ready: Database transactions, row locking, minor units handling, and comprehensive error handling

Requirements

  • PHP 8.2+
  • Laravel 12+

Installation

Install the package via Composer:

composer require zfhassaan/laravel-wallet

Publish the configuration file (optional):

php artisan vendor:publish --tag=laravel-wallet-config

Run the migrations:

php artisan migrate

Quick Start

1. Add the Trait to Your User Model

use Zfhassaan\LaravelWallet\Traits\HasWallets;

class User extends Authenticatable
{
    use HasWallets;
}

2. Create a Wallet

use LaravelWallet;

$wallet = LaravelWallet::createWallet($user);

3. Credit the Wallet

// Amount in minor units (paisa for PKR, cents for USD)
// 1000 = 10.00 PKR (assuming 100:1 conversion rate)
LaravelWallet::credit($wallet, 1000);

4. Get Balance

$balance = LaravelWallet::balance($wallet); // Returns balance in minor units

5. Transfer Funds

$result = LaravelWallet::transfer($fromWallet, $toWallet, 500);
// Returns array with 'debit' and 'credit' transactions

Core Concepts

Ledger-Based System

Unlike traditional wallet systems that store balance in a mutable column, Laravel Wallet calculates balance from transaction records:

Balance = SUM(credits) - SUM(debits)

This approach provides:

  • Audit Safety: Every transaction is immutable and traceable
  • Race Condition Prevention: Row-level locking ensures consistency
  • Tamper Detection: Balance hash validation detects any unauthorized changes

Minor Units

All amounts are stored in minor units (e.g., paisa for PKR, cents for USD). This eliminates floating-point precision issues and ensures accurate financial calculations.

// 10.00 PKR = 1000 paisa (with 100:1 conversion rate)
LaravelWallet::credit($wallet, 1000);

Conversion Rates

Control how wallet values are represented with flexible conversion rates:

// Set conversion rate (100 = 100 paisa = 1 PKR)
LaravelWallet::setConversionRate($wallet, 100);

// Or create wallet with custom rate
$wallet = LaravelWallet::createWallet($user, 'PKR', [
    'conversion_rate' => 10 // 10:1 ratio
]);

// Convert between major and minor units
$majorUnits = LaravelWallet::toMajorUnits($wallet, 1000); // 10.0
$minorUnits = LaravelWallet::toMinorUnits($wallet, 10.0); // 1000

Common Operations

Credit Wallet

LaravelWallet::credit($wallet, 1000, 'payment-ref-123', [
    'description' => 'Payment received',
    'source' => 'payment_gateway'
]);

Debit Wallet

LaravelWallet::debit($wallet, 500, 'purchase-ref-456', [
    'product_id' => 123,
    'order_id' => 789
]);

Check Balance

$balance = LaravelWallet::balance($wallet);

// Check if sufficient balance exists
$hasEnough = LaravelWallet::assertSufficientBalance($wallet, 1000);

Validate Wallet Integrity

$validation = LaravelWallet::validateWallet($wallet);

if (!$validation['valid']) {
    // Wallet has been tampered with
    // Automatically frozen by the package
}

Freeze/Unfreeze Wallet

// Freeze wallet (prevents all operations)
LaravelWallet::freeze($wallet, 'Suspicious activity detected');

// Unfreeze wallet
LaravelWallet::unfreeze($wallet, 'Issue resolved');

QR Payments

// Generate QR payment
$qrPayment = LaravelWallet::generateQrPayment(
    $wallet, 
    1000, 
    'Payment for order #123',
    30 // expires in 30 minutes
);

// Process QR payment
$result = LaravelWallet::processQrPayment(
    $payerWallet, 
    $qrPayment['qr_code']
);

Wallet Profile

$profile = LaravelWallet::profile($wallet);

// Returns comprehensive wallet information:
// - Balance
// - Currency
// - Status
// - Transaction count
// - Last transaction
// - Conversion rate
// - Services enabled

Advanced Features

Rate Limiting

Prevent abuse by setting rate limits on wallet operations:

LaravelWallet::setRateLimit($wallet, 'credit', 10, 'hour'); // 10 credits per hour
LaravelWallet::setRateLimit($wallet, 'debit', 20, 'day');  // 20 debits per day

Wallet Services

Enable or disable specific services for a wallet:

LaravelWallet::enableService($wallet, 'transfers');
LaravelWallet::enableService($wallet, 'qr_payments');
LaravelWallet::disableService($wallet, 'external_credits');

Password Protection

Add an extra layer of security with wallet passwords:

LaravelWallet::password($wallet, 'secure-password-123', [
    'require_for_debit' => true,
    'require_for_transfer' => true
]);

External Credits

Use sendCredit() for system/external credits that bypass rate limits:

LaravelWallet::sendCredit($wallet, 1000, 'system-bonus', [
    'type' => 'referral_bonus',
    'campaign_id' => 456
]);

Exception Handling

The package provides specific exceptions for better error handling:

use Zfhassaan\LaravelWallet\Exceptions\WalletTamperedException;
use Zfhassaan\LaravelWallet\Exceptions\RateLimitExceededException;

try {
    LaravelWallet::debit($wallet, 1000);
} catch (WalletTamperedException $e) {
    // Wallet integrity compromised
} catch (RateLimitExceededException $e) {
    // Rate limit exceeded
} catch (InsufficientBalanceException $e) {
    // Not enough balance
}

Configuration

After publishing the configuration file, you can customize various settings:

// config/laravel-wallet.php

return [
    'default_currency' => 'PKR',
    'default_conversion_rate' => 100,
    'tables' => [
        'wallets' => 'wallets',
        'transactions' => 'wallet_transactions',
        // ... other tables
    ],
    'rate_limiting' => [
        'enabled' => true,
        'default_limit' => 100,
        'default_period' => 'hour',
    ],
    // ... more configuration options
];

Testing

Run the test suite:

composer test

Or with PHPUnit directly:

vendor/bin/phpunit

Documentation

Complete documentation is available in the docs/ directory. You can also view it online by serving the documentation:

cd docs
php -S localhost:8000

Then visit http://localhost:8000 in your browser.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Security

If you discover any security-related issues, please email zfhassaan@gmail.com instead of using the issue tracker.

License

This package is open-sourced software licensed under the MIT license.

Support

Credits

Built with ❤️ for the Laravel community