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
Requires
- php: ^8.2
- laravel/framework: ^12.0
- simplesoftwareio/simple-qrcode: ^4.2
Requires (Dev)
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.0
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.
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.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - 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
- GitHub Issues: Report a bug or request a feature
- Packagist: View on Packagist
Credits
- Author: Hassaan Ali
- Package: Laravel Wallet
Built with ❤️ for the Laravel community