3neti / wallet
Custom wallet for X-Change
Requires
- php: ^8.3
- bavix/laravel-wallet: ^11.4
- brick/money: ^0.10.1
- laravel/framework: ^12.0 || ^13.0
- lorisleiva/laravel-actions: ^2.9
- spatie/laravel-data: ^4.15
Requires (Dev)
- orchestra/testbench: ^10.3 || ^11.0
- pestphp/pest: ^3.8 || ^4.0
This package is auto-updated.
Last update: 2026-08-19 03:18:04 UTC
README
3neti/wallet is the provider-neutral value-accounting and Treasury position
layer used by x-change. It extends
Bavix Laravel Wallet with explicit
system-principal resolution, durable Treasury Inventory, principal Positions,
and append-only recognition, reservation, release, allocation, reversal, and
derecognition operations.
The package records internal financial attribution. It does not call banks, EMIs, payout providers, or webhook endpoints.
Supported platforms
- PHP 8.3 and 8.4
- Laravel 12 and 13
- Bavix Laravel Wallet 11
Laravel 12 and Laravel 13 are tested as separate compatibility lanes.
Installation
composer require 3neti/wallet:^2.0@beta php artisan migrate
Laravel package discovery registers
LBHurtado\Wallet\WalletServiceProvider. The provider loads the package-owned
Treasury migrations and the Bavix provider continues to own its wallet,
transaction, and transfer migrations.
Publish configuration only when the application needs to override the package defaults:
php artisan vendor:publish --provider="LBHurtado\Wallet\WalletServiceProvider" --tag=config
Published files:
config/account.phpconfig/wallet.php
Schema ownership
The package owns these Treasury tables:
treasury_settlement_resourcestreasury_inventoriestreasury_inventory_operationstreasury_positionstreasury_position_operations
The migrations are additive. Applications must run php artisan migrate after
installing or upgrading the package. Do not copy or rename package migrations
inside the host application.
Bavix continues to own the underlying wallet ledgers, transactions, and transfers. Treasury records reference those ledgers without exposing internal wallet identifiers through the package read models.
Accounting model
Provider evidence
│
▼
Treasury Inventory
│
├── Client Funds
├── Pay Code Reserve
├── Account Funding Reserve
├── Provider Cost
├── Product Revenue
├── Partner Commission
└── Commercial Revenue
- Inventory is recognized provider value available to the settlement system.
- Positions attribute that Inventory to a principal, purpose, provider connection, and currency.
- Operations are append-only and idempotent.
- Planning contracts are non-mutating. Their default runtimes fail closed by returning no executable plan.
- Read models omit internal Bavix ledger identifiers.
The integrating settlement package remains responsible for authenticating
provider evidence, enforcing authorization, and deciding when an operation is
permitted. 3neti/wallet records the resulting accounting operation; it does
not manufacture settlement authority.
System principal
Applications should resolve their system principal through
SystemUserResolverContract:
use LBHurtado\Wallet\Contracts\SystemUserResolverContract; $systemPrincipal = app(SystemUserResolverContract::class)->resolve();
The legacy single-candidate configuration remains available:
'system_user' => [ 'model' => App\Models\User::class, 'identifier_column' => 'email', 'identifier' => env('SYSTEM_USER_ID'), 'candidates' => [], ],
An integrating package may supply multiple named candidates that all identify
the same principal. Resolution fails closed when candidates disagree, a model
does not implement the Bavix Wallet contract, an identifier column is unsafe,
or no principal is found.
Resolve the contract through Laravel's container. Direct construction of
SystemUserResolverService and actions that consume it is not part of the 2.x
public API.
Runtime contracts
The service provider binds contracts for:
- Treasury Inventory reads and operations;
- Treasury Position provisioning, reads, and operations;
- Inventory-to-Position portfolio reads;
- commercial allocation reads;
- Treasury planning;
- operation planning; and
- sensitive metadata sanitization.
Provider packages should implement or decorate these contracts rather than add provider-specific behavior to this package.
Security boundaries
- Amounts are persisted in integer minor units.
- Inventory and Position mutations are append-only and idempotent.
- Conflicting reuse of an operation reference fails closed.
- Metadata keys configured in
wallet.treasury.sensitive_metadata_keysare recursively redacted before persistence. - Provider credentials, raw provider responses, Pay Codes, and inspection tokens must not be stored in Treasury metadata.
- Top-up helpers transfer existing value from the resolved system principal; they do not create provider value.
Upgrade from 1.x
Version 2 is a deliberate major-version boundary.
Before upgrading:
- update every direct consumer to accept
3neti/wallet:^2.0@beta; - remove direct construction of
SystemUserResolverServiceandTopupWalletAction; - resolve their contracts or actions through Laravel's container;
- review the configured system-principal candidates;
- run the package migrations; and
- reconcile Treasury Inventory and Positions before enabling issuance.
Do not infer opening Inventory from a Bavix balance. Opening recognition must come from an authorized, provider-backed reconciliation workflow owned by the integrating settlement system.
Testing
composer install
composer test
The package suite covers legacy Bavix wallet behavior, system-principal resolution, Treasury DTOs and contracts, durable Inventory and Position operations, commercial waterfall positions, idempotency, reversals, and metadata sanitization.
CI runs the suite against every supported Laravel generation. A release tag is created only after downstream clean-consumer tests pass.
License
MIT