Guide
Equal-split payment maths: dividing USDT without losing a cent
How to divide a USDT total evenly across recipients using integer sun arithmetic, handle remainders explicitly, apply platform fees consistently, and keep every batch reconcilable.
Last updated August 2026
Quick answer
Divide a USDT total by converting it to integer sun, the smallest unit worth one millionth of a token, dividing by the recipient count and taking the floor. Assign the remainder explicitly to a named destination. Never use floating point, because binary fractions cannot represent decimal money exactly.
- USDT has six decimals, so one token is one million sun.
- Floating point division introduces errors that break reconciliation.
- The remainder is always smaller than the recipient count in sun and must be assigned deliberately.
- Fee-inside versus fee-on-top changes take-home pay and must be decided before calculating.
Why money maths deserves attention
Splitting a number by a number sounds like the least interesting part of a payout system, right up until the on-chain total does not match the accounting total and somebody has to explain the difference. Small arithmetic decisions compound into reconciliation problems, and reconciliation problems consume far more time than getting the maths right in the first place.
The two recurring mistakes are using floating point arithmetic for currency and letting a remainder disappear without deciding where it went. Both are easy to avoid once you know they exist.
The goal is a batch where the sum of every recipient amount, plus the fee, equals the total moved by the transaction, exactly, every time.
Working in sun, not in tokens
USDT on Tron carries six decimal places. The token contract stores balances as integers in the smallest unit, so one USDT is one million of those units. Tron tooling generally calls that unit sun.
All internal arithmetic should happen in those integers. Take the human-entered total, convert it once at the boundary, do every calculation in integers, and convert back only for display. This is the same discipline that financial systems apply with minor units such as cents, and it exists for the same reason.
Because the numbers can exceed what a standard double-precision float represents safely, use an arbitrary precision integer type for the arithmetic. Modern JavaScript provides BigInt, which is exactly the right tool.
- One USDT equals 1,000,000 sun.
- Convert human input to sun once, at the edge of the system.
- Use BigInt or an equivalent, never a floating point number.
What goes wrong with floating point
Binary floating point cannot represent most decimal fractions exactly. The classic demonstration is that adding a tenth to two tenths does not produce exactly three tenths. In a payout system this shows up as a per-recipient amount with a long tail of digits, which then gets rounded somewhere unpredictable.
Once rounding happens implicitly, the sum of the parts stops equalling the whole. With ten recipients the discrepancy is invisible. With a thousand it is a real number, and it is the kind of number auditors ask about.
Integer arithmetic sidesteps the entire category. There is no representation error to accumulate, because every value is exact by construction.
Dividing and handling the remainder
The calculation itself is simple. Take the total in sun, divide by the number of recipients using integer division, and that is each person's share. Multiply the share by the count and subtract from the total, and what is left is the remainder.
The remainder is always strictly less than the recipient count, measured in sun, so at most a few hundredths of a cent for a normal batch. Its size is irrelevant; its treatment is not. It must go somewhere named, and the interface should say where.
Reasonable policies include adding it to the first recipient, adding it to the last, or routing it to the fee wallet. Pick one, state it on screen, and apply it consistently. What is not acceptable is letting it vanish, because then the sums stop tying out.
Fees: inside the pool or on top
If a platform fee applies, decide whether it comes out of the total being distributed or is added to it. Taking it from the pool means recipients share a smaller amount. Adding it on top means the operator funds more than the headline figure.
Compute the fee first, in integers, using the same flooring discipline. Then split what remains. Doing it in the other order, splitting first and then skimming, produces different rounding and makes the per-person amount harder to explain.
Show all three numbers before signing: total funded, fee, and per-recipient share. Anyone reviewing the batch can then verify the relationship in their head, which is exactly the kind of check that catches configuration errors.
Displaying amounts honestly
Convert back to decimal only for display, and show the full six decimals when precision matters. Truncating to two decimals in the interface while sending six creates a mismatch between what the operator approved and what the chain executed.
Where a shortened display is genuinely more readable, make the exact value available on hover or in the detail view. The rule is that the precise number must always be reachable, not that it must always be prominent.
Use the same formatting in the batch history as in the confirmation screen. Different formatting in different places is how people convince themselves a discrepancy exists when it does not.
Validating before signing
A batch is arithmetically sound when three checks pass. The sum of recipient amounts plus the fee equals the total. Every individual amount is greater than zero. The recipient count matches the number of validated rows.
Run these as code, not as a human glance. They are cheap, they are deterministic, and they catch the situation where a rounding change or an off-by-one in the recipient list has quietly altered the outcome.
If any check fails, refuse to sign rather than warning. A payout tool that lets you proceed past a failed arithmetic invariant is not helping you.
Reconciling afterwards
Store the total, the fee, the recipient count, the per-recipient share and the remainder policy with the batch record. Those five values fully describe the arithmetic and let anyone reproduce it later without access to the original interface.
On the chain side, the transaction shows the total moved and the individual transfers. Comparing your stored sum against the on-chain total is a complete reconciliation, and it should match to the sun.
When it does not match, the difference itself is diagnostic. A shortfall equal to the remainder points at a dropped remainder. A shortfall equal to one share points at a recipient that failed validation after the total was set.
Ready to run your first batch?
Test on Shasta, then switch to mainnet with the same flow and the same wallet.
Create your account