The life of a payment
What happens between money arriving and everyone being paid.
From one payment to many
- 1
Someone pays the split
Tokens arrive at its address, like any wallet.
- 2
The rule divides it
The contract computes every share; nobody types amounts.
- 3
Checks run
Large payouts wait for signatures; frozen ones wait too.
- 4
Everyone is paid
One transaction pays all and logs a receipt.
The three rules, worked out
Say 2,500 tUSDC arrives.
Fixed percentages
Shares add up to exactly 100%.
| Recipient | Share | Receives |
|---|---|---|
| Events & venues | 40% | 1,000 tUSDC |
| Workshop instructors | 30% | 750 tUSDC |
| Hackathon prize pool | 20% | 500 tUSDC |
| Club treasury | 10% | 250 tUSDC |
Contribution points
Each share is points ÷ total points.
| Recipient | Share | Receives |
|---|---|---|
| Léa Tremblay | 34 / 97 | 876.288661 tUSDC |
| Omar Haddad | 28 / 97 | 721.649484 tUSDC |
| Priya Nair | 22 / 97 | 567.010309 tUSDC |
| Jonas Weber | 13 / 97 | 335.051546 tUSDC |
Cover a cost first
A fixed amount first, then the rule.
| Recipient | Share | Receives |
|---|---|---|
| Shared rent | — | 350 tUSDC |
| Growers' collective | 45% | 967.5 tUSDC |
| Rise & Crumb bakery | 25% | 537.5 tUSDC |
| Northside coffee roaster | 20% | 430 tUSDC |
| Community fund | 10% | 215 tUSDC |
Rounding dust
Shares round down; the few leftover units go to the largest share, shown on the receipt.
Approvals and freezing
Approvals for large payouts
Above a threshold, a payout waits for enough signers, e.g. 2 of 3 from 2,000 tUSDC.
Emergency freeze
The owner or an approver can stop payouts. Payments are held until unfrozen.
The audit trail
Every event, with time, actor, amount and transaction hash. Exports to CSV.
For developers
The demo runs in your browser; its data layer mirrors the contract, ready for wagmi and viem.
Show the contract interface
Contract interface (sketch)
interface ISplit {
// Rule: fixed basis points (sum 10_000) or points
function recipients() external view returns (address[] memory, uint256[] memory);
function coverFirst() external view returns (address, uint256);
// Anyone can pay the split like any wallet
receive() external payable;
// Pays every recipient their share of what is waiting.
// Rounds down; the dust goes to the largest share.
function distribute(uint256 amount) external;
// Payouts >= threshold need `required` approvals
function propose(uint256 amount) external returns (uint256 id);
function approve(uint256 id) external; // executes on the last approval
function freeze() external; // owner or approver
function unfreeze() external;
event PaymentReceived(address indexed from, uint256 amount);
event Distributed(uint256 amount, address[] to, uint256[] amounts);
event Frozen(address by);
}The demo's data layer
src/lib/demo/types.tssplits, rules and audit entries, in base unitssrc/lib/demo/allocate.tsthe exact division, dust includedsrc/lib/demo/ops.tspayment, payout, approval, freezesrc/lib/demo/chain.tssimulated wallet, blocks and failures