PHPackages                             huoxin/money-with-history - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. huoxin/money-with-history

ActiveFlarum-extension[Utility &amp; Helpers](/categories/utility)

huoxin/money-with-history
=========================

A unified Flarum extension that adds a virtual currency system with full transaction history tracking.

1.1.2(1w ago)0140↑437.5%MITPHPCI passing

Since May 23Pushed 1w agoCompare

[ Source](https://github.com/huoxin233/flarum-ext-money-with-history)[ Packagist](https://packagist.org/packages/huoxin/money-with-history)[ RSS](/packages/huoxin-money-with-history/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (4)Dependencies (2)Versions (5)Used By (0)

Money With History
==================

[](#money-with-history)

[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667) [![Latest Stable Version](https://camo.githubusercontent.com/a52d4f5f3c05d0c0fbf72a8a84675ba398b5cc9ca7ef027f35242691a2a3ac83/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68756f78696e2f6d6f6e65792d776974682d686973746f72792e737667)](https://packagist.org/packages/huoxin/money-with-history) [![Total Downloads](https://camo.githubusercontent.com/5df8bc2bf9ac2ab947ae0846779de4e2fdb73f7efe0338ed7fe524a31d53d993/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68756f78696e2f6d6f6e65792d776974682d686973746f72792e737667)](https://packagist.org/packages/huoxin/money-with-history) [![Review](https://camo.githubusercontent.com/9ad0c07367b06e265aa474344554b05dd8cb25f7ce03b15b0c2c7e3e6e600999/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f68756f78696e2f6d6f6e65792d776974682d686973746f72792f62616467652f726576696577)](https://floxum.com/extension/huoxin/money-with-history) [![Review Score](https://camo.githubusercontent.com/b7739a77077dbc4dfbfd26c1b07adda25ebf48bf6fd5c34006b7049903aaa4a7/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f68756f78696e2f6d6f6e65792d776974682d686973746f72792f62616467652f7265766965772d73636f7265)](https://floxum.com/extension/huoxin/money-with-history)

A [Flarum](https://flarum.org) extension that adds a virtual currency system with full transaction history tracking.

As discussed [here](https://github.com/AntoineFr/flarum-ext-money/pull/52), this extension would be a merge of [`antoinefr/flarum-ext-money`](https://github.com/AntoineFr/flarum-ext-money) and [`mattoid/flarum-ext-money-history`](https://github.com/mattoid/flarum-ext-money-history) into a single, standalone package so no cross-extension dependency management is required. With this extension, I hope that we can eliminate the need of [`mattoid/flarum-ext-money-history-auto`](https://github.com/Mattoids/flarum-ext-money-history-auto) which relies on middleware to intercept API requests and record balance changes. However, achieving full compatibility will require support and integration from other extension developers.

🎉 Credits to: [AntoineFr](https://github.com/AntoineFr) and [Mattoid](https://github.com/Mattoids) and all contributors involved in those extensions

Features
--------

[](#features)

- Award money for posts, discussions, and likes
- Configurable auto-removal when content is hidden or deleted
- Cascade removal for posts when a discussion is deleted
- Minimum post length requirement
- Manual balance editing by moderators
- **Full balance history**
- Per-tag money disable permission

Installation
------------

[](#installation)

```
composer require huoxin/money-with-history
php flarum migrate
php flarum cache:clear
```

Updating
--------

[](#updating)

```
composer update huoxin/money-with-history
php flarum migrate
php flarum cache:clear
```

Migrating From Legacy Extensions
--------------------------------

[](#migrating-from-legacy-extensions)

Do note that some of the more complex ones are **not covered**, you will have to manually migrate it yourself if you want a 100% clean money history.

Important

Enabling this extension for the first time will run migration tasks automatically. If you previously had a large money history database, the process may take some time to complete. It is recommended to enable the extension via CLI:

```
php flarum extension:enable huoxin-money-with-history
```

If you were previously using `antoinefr/flarum-ext-money` and/or `mattoid/flarum-ext-money-history`:

1. **Backup your database**.
2. Install this extension alongside the old ones.
3. Run `php flarum migrate` — idempotent migrations will:
    - Add the `money` column and `user_money_history` table if missing
    - Rename legacy columns (`type` → `source`, `money` → `balance_delta`, etc.)
    - Normalize `source` values (e.g. `POSTWASPOSTED` → `POST_POSTED`)
    - Migrate `source_key` translation prefixes to `huoxin-money-with-history.forum.money-history.*`
    - Copy settings keys from `antoinefr-money.*` and `money-history.*` to `huoxin-money-with-history.*`
4. Disable and uninstall the old extensions.

Legacy data from the deprecated `mattoid-money-history-auto` extension is also migrated.

For Other Extension Authors
---------------------------

[](#for-other-extension-authors)

This extension is the main balance-changing entry point. Other extensions should inject:

```
use Huoxin\MoneyWithHistory\Service\BalanceManager;
```

### Available Methods

[](#available-methods)

#### Method comparison

[](#method-comparison)

MethodTransactionRow lockSaves userBest for`adjustBalance()`Opens its ownLocks internallyYes, internallyStandalone one-user changes`adjustBalances()`Opens its ownLocks all rowsYes, internallyBatch rewards / bulk grants`transferBalance()`Opens its ownLocks both usersYes, internallyUser-to-user transfers`applyBalanceChange()`**You provide****You lock****You call** `$user->save()`Saving money alongside your own domain fields#### `adjustBalance()`

[](#adjustbalance)

Single user balance change. Opens a transaction, locks the user row, updates the balance, writes history, and dispatches events — all self-contained.

```
$this->balances->adjustBalance(
    $user,
    -12.5,
    'MYEXTENSION_PURCHASE',
    'vendor-my-extension.forum.money-history.purchase',
    ['itemTitle' => 'VIP Badge'],
    $actor,
    preventOverdraft: true
);
```

Returns `false` if the user has insufficient balance (when `preventOverdraft` is enabled).

#### `adjustBalances()`

[](#adjustbalances)

Batch update for multiple users in a single transaction. Preferred for system rewards and bulk grants.

**Best Practice:** If processing thousands of users simultaneously, chunk your input array (e.g., 500 users per call). This prevents PHP memory exhaustion and prevents MySQL lock exhaustion (since all rows are locked simultaneously during the transaction).

```
$totalUpdated = 0;

// Fetch and process users using chunkById to preserve memory and prevent lock exhaustion
User::query()->where('is_vip', true)->chunkById(500, function ($users) use (&$totalUpdated, $actor) {
    $totalUpdated += $this->balances->adjustBalances(
        $users->all(), // Convert Eloquent Collection to array
        5.0,
        'DAILY_REWARD',
        'vendor-my-extension.forum.money-history.daily-reward',
        [],
        $actor
    );
});
```

Returns the count of users actually updated. Silently skips users who can't afford the debit when `preventOverdraft` is enabled.

#### `transferBalance()`

[](#transferbalance)

Atomic user-to-user transfer. Always prevents overdraft on the sender side.

```
$this->balances->transferBalance(
    $sender,
    $receiver,
    25.0,
    'MYEXTENSION_TRANSFER',
    'vendor-my-extension.forum.money-history.sent',
    'vendor-my-extension.forum.money-history.received',
    [
        'giverUsername' => $sender->username,
        'receiverUsername' => $receiver->username,
    ],
    $actor
);
```

#### `applyBalanceChange()`

[](#applybalancechange)

Use when your extension already manages its own database transaction and needs to persist the balance change alongside other domain fields atomically.

Unlike `adjustBalance()` which opens its own transaction and calls `save()` internally, `applyBalanceChange()` only mutates `$user->money` on the model object. History recording and event dispatching are deferred to an Eloquent `afterSave` callback — they only execute after your `$user->save()` succeeds. If the save fails or the transaction rolls back, no orphaned history row is written.

**The caller is responsible for:**

1. Opening a database transaction
2. Locking the user row (`SELECT ... FOR UPDATE`)
3. Calling `$user->save()` after this method

```
$this->connection->transaction(function () use ($user, $actor) {
    $lockedUser = User::query()->whereKey($user->id)->lockForUpdate()->first();

    // Your domain field
    $lockedUser->last_checkin_time = now();

    // Mutates $lockedUser->money on the model — does NOT save or write history yet
    $this->balances->applyBalanceChange(
        $lockedUser,
        5.0,
        'DAILY_CHECKIN_REWARD',
        'vendor-my-extension.forum.history.checkin-reward',
        ['streakDays' => 7],
        $actor
    );

    // One save persists both last_checkin_time AND money atomically.
    // The afterSave callback then writes the history row and dispatches MoneyUpdated.
    $lockedUser->save();
});
```

### `source`, `sourceKey`, `sourceParams`

[](#source-sourcekey-sourceparams)

FieldPurposeExample`source`Stable machine-readable identifier`STORE_BUY_GOODS``sourceKey`Frontend translation key`vendor-ext.forum.money-history.purchase``sourceParams`Flat key-value data for the translation`['itemTitle' => 'VIP Badge']`**`sourceParams` conventions:**

- Plain values: `itemTitle`, `postNumber`, `username`
- Translated values: keys ending with `Key` (e.g. `purchaseTypeKey`)
- Link values: keys ending with `LinkHref` (e.g. `itemLinkHref`)

### Optional Integration (Soft Dependency)

[](#optional-integration-soft-dependency)

If your extension wants to offer money features without requiring this extension:

```
use Huoxin\MoneyWithHistory\Service\BalanceManager;

if ($this->extensions->isEnabled('huoxin-money-with-history')) {
    $balanceManager = $this->container->make(BalanceManager::class);
    $balanceManager->applyBalanceChange(...);
}
```

Concurrency And Locking
-----------------------

[](#concurrency-and-locking)

`BalanceManager` locks affected user rows during write transactions to keep balance snapshots consistent.

- Prefer `adjustBalances()` and `transferBalance()` over hand-written loops
- Keep transaction work small and avoid slow side effects inside it

Screenshots
-----------

[](#screenshots)

[![image](https://private-user-images.githubusercontent.com/23447157/597330620-f7713ae4-25a7-4598-80d5-b8a68ef281ce.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODAzODY1NTgsIm5iZiI6MTc4MDM4NjI1OCwicGF0aCI6Ii8yMzQ0NzE1Ny81OTczMzA2MjAtZjc3MTNhZTQtMjVhNy00NTk4LTgwZDUtYjhhNjhlZjI4MWNlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA2MDIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNjAyVDA3NDQxOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdhNGRhOTJjYmE1MjliOWFiYTU1NzhhZjA5OTJkNDBiYzkxM2UwZWRiZGQzYTM5MDZkMTRjYzVmMDE4OTA2OGMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.tm5-7vPPVn2pyG3_Fwb3eGL1JMo6d5sC9sszenwp2_g)](https://private-user-images.githubusercontent.com/23447157/597330620-f7713ae4-25a7-4598-80d5-b8a68ef281ce.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODAzODY1NTgsIm5iZiI6MTc4MDM4NjI1OCwicGF0aCI6Ii8yMzQ0NzE1Ny81OTczMzA2MjAtZjc3MTNhZTQtMjVhNy00NTk4LTgwZDUtYjhhNjhlZjI4MWNlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA2MDIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNjAyVDA3NDQxOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdhNGRhOTJjYmE1MjliOWFiYTU1NzhhZjA5OTJkNDBiYzkxM2UwZWRiZGQzYTM5MDZkMTRjYzVmMDE4OTA2OGMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.tm5-7vPPVn2pyG3_Fwb3eGL1JMo6d5sC9sszenwp2_g)[![image](https://private-user-images.githubusercontent.com/23447157/597337812-d0aea471-f8e1-4cc5-a5b9-0a58fe6b7ef4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODAzODY1NTgsIm5iZiI6MTc4MDM4NjI1OCwicGF0aCI6Ii8yMzQ0NzE1Ny81OTczMzc4MTItZDBhZWE0NzEtZjhlMS00Y2M1LWE1YjktMGE1OGZlNmI3ZWY0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA2MDIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNjAyVDA3NDQxOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0N2ExNzY5YWM4MTc1ZDE1YjVlY2EyZjM1NmNjNTdiMTQ5Nzg0YzZlOGNiZDYxNzYxYzIxNjM0ZmFiOTViMzImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.sKm5wpwZ7LPNIqWicUFKVLi09VJ1XGzaKWgErXZ2GYA)](https://private-user-images.githubusercontent.com/23447157/597337812-d0aea471-f8e1-4cc5-a5b9-0a58fe6b7ef4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODAzODY1NTgsIm5iZiI6MTc4MDM4NjI1OCwicGF0aCI6Ii8yMzQ0NzE1Ny81OTczMzc4MTItZDBhZWE0NzEtZjhlMS00Y2M1LWE1YjktMGE1OGZlNmI3ZWY0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA2MDIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNjAyVDA3NDQxOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0N2ExNzY5YWM4MTc1ZDE1YjVlY2EyZjM1NmNjNTdiMTQ5Nzg0YzZlOGNiZDYxNzYxYzIxNjM0ZmFiOTViMzImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.sKm5wpwZ7LPNIqWicUFKVLi09VJ1XGzaKWgErXZ2GYA)Links
-----

[](#links)

- [Packagist](https://packagist.org/packages/huoxin/money-with-history)
- [GitHub](https://github.com/huoxin233/flarum-ext-money-with-history)
- [Discuss](https://discuss.flarum.org/d/39319-money-with-history)

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance98

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 88.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

4

Last Release

10d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/23447157?v=4)[huoxin](/maintainers/huoxin233)[@huoxin233](https://github.com/huoxin233)

---

Top Contributors

[![huoxin233](https://avatars.githubusercontent.com/u/23447157?v=4)](https://github.com/huoxin233 "huoxin233 (39 commits)")[![flarum-bot](https://avatars.githubusercontent.com/u/39334649?v=4)](https://github.com/flarum-bot "flarum-bot (5 commits)")

---

Tags

moneycurrencyhistoryflarumbalance

### Embed Badge

![Health badge](/badges/huoxin-money-with-history/health.svg)

```
[![Health](https://phpackages.com/badges/huoxin-money-with-history/health.svg)](https://phpackages.com/packages/huoxin-money-with-history)
```

###  Alternatives

[brick/money

Money and currency library

1.9k40.4M139](/packages/brick-money)[florianv/swap

PHP currency conversion library for retrieving exchange rates from 30 providers, with caching and fallback.

1.3k6.7M22](/packages/florianv-swap)[cknow/laravel-money

Laravel Money

1.0k4.6M29](/packages/cknow-laravel-money)[akaunting/laravel-money

Currency formatting and conversion package for Laravel

7855.7M42](/packages/akaunting-laravel-money)[kwn/number-to-words

Multi language standalone PHP number to words converter. Fully tested, open for extensions and new languages.

4275.3M23](/packages/kwn-number-to-words)[torann/currency

This provides Laravel with currency functions such as currency formatting and conversion using up-to-date exchange rates.

4031.1M6](/packages/torann-currency)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
