|
1 | | -# PaySplit |
| 1 | +# PaySplit — proportional revenue splitter (Aptos Move) |
2 | 2 |
|
3 | | -Payment splitter: deposits are split across recipients proportionally to their shares. |
4 | | -Remainders (from integer division) accumulate as admin fees (withdrawable). |
| 3 | +> Simple, gas-friendly splitter: deposits are split among recipients by fixed integer shares. |
| 4 | +> Integer remainder (from floor division) is accumulated as **fees** for the admin. |
| 5 | +
|
| 6 | +- **Module:** `PaySplit::split` |
| 7 | +- **Status:** compiles; CI green |
| 8 | +- **Use cases:** payout royalties, split protocol revenue, team distributions |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## Data model |
| 13 | + |
| 14 | +- `struct Splitter {` |
| 15 | + - `admin: address` — package address that owns the splitter |
| 16 | + - `recipients: vector<address>` — payout accounts |
| 17 | + - `shares: vector<u64>` — integer weights per recipient |
| 18 | + - `total_shares: u64` — sum(shares), precomputed |
| 19 | + - `balances: vector<Balance>` — internal pending balances |
| 20 | + - `fees_accumulated: u64` — remainder bucket (see math below) |
| 21 | +- `struct Balance { owner: address, amount: u64 }` |
| 22 | + |
| 23 | +**Math:** for each deposit `amount`, each recipient `i` gets |
| 24 | +`part_i = (amount * shares[i]) / total_shares` (floor division). |
| 25 | +Remainder `amount - sum(part_i)` goes to `fees_accumulated` and can later be claimed by admin. |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## Public API (entries) |
| 30 | + |
| 31 | +- `init(admin: &signer, recipients: vector<address>, shares: vector<u64>)` |
| 32 | + - One-time init stored under `address_of(admin)`. |
| 33 | + - Fails if `recipients.is_empty()`, length mismatch, or already initialized. |
| 34 | + |
| 35 | +- `deposit(payer: &signer, admin_addr: address, amount: u64)` |
| 36 | + - Splits `amount` to recipients’ internal balances; pushes remainder to `fees_accumulated`. |
| 37 | + |
| 38 | +- `withdraw(rcpt: &signer, admin_addr: address)` |
| 39 | + - Sets caller’s internal balance to `0` (demo accounting). You can wire real coin/NFT logic later. |
| 40 | + |
| 41 | +- `withdraw_fees(admin: &signer, admin_addr: address)` |
| 42 | + - Moves `fees_accumulated` into admin’s internal balance. Only admin may call. |
| 43 | + |
| 44 | +- `view_balance(admin_addr: address, owner: address): u64` |
| 45 | + - Read internal balance for any address. |
| 46 | + |
| 47 | +**Error codes** |
| 48 | +- `E_ALREADY_INIT = 1`, `E_EMPTY = 2`, `E_LEN_MISMATCH = 3`, `E_NOT_ADMIN = 4` |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## Quick start (local) |
5 | 53 |
|
6 | | -## Quick run |
7 | 54 | ```bash |
| 55 | +# 1) Compile & run unit tests (if any) |
| 56 | +cd paysplit |
8 | 57 | aptos move compile |
9 | 58 | aptos move test --filter . |
10 | 59 |
|
| 60 | +# 2) Publish on devnet (from your Aptos profile) |
| 61 | +aptos move publish --assume-yes |
| 62 | + |
| 63 | +# Copy the published package address (we'll call it <PKG>) |
| 64 | +# 3) Initialize splitter (example: 3 recipients with shares 50/30/20) |
| 65 | +aptos move run \ |
| 66 | + --function-id <PKG>::split::init \ |
| 67 | + --args 'vector<address>:@0xA,@0xB,@0xC' 'vector<u64>:50,30,20' |
| 68 | + |
| 69 | +# 4) Deposit 100 (splits to 50/30/20; remainder 0) |
| 70 | +aptos move run \ |
| 71 | + --function-id <PKG>::split::deposit \ |
| 72 | + --args "address:<PKG>" "u64:100" |
| 73 | + |
| 74 | +# 5) Admin converts remainder to balance (useful for small deposits with remainder) |
| 75 | +aptos move run \ |
| 76 | + --function-id <PKG>::split::withdraw_fees \ |
| 77 | + --args "address:<PKG>" |
| 78 | + |
| 79 | +# 6) Read balances (from a script or view; here conceptual) |
| 80 | +# view_balance(<PKG>, @0xA) == 50, @0xB == 30, @0xC == 20 |
| 81 | + |
| 82 | + |
11 | 83 | ## Contacts |
12 | 84 | - Discord: [@rootmhz_](https://discord.com/users/1047911417396875264) |
13 | 85 | - Telegram: [@Nikolai_Rootmhz](https://t.me/Nikolai_Rootmhz) |
|
0 commit comments