Transactions and payouts

The escrow ledger leg by leg, how verifying a delivery pays the creator, how rejecting one refunds the buyer and restores supply, and every path money can take out of an ICO.

5 min readUpdated 3 August 2026admin, escrow, payouts, refunds, fees

The transaction desk at Admin → ICO → Transactions is where escrow is released or handed back. It needs access.ico.transaction and view.ico.transaction to open, and edit.ico.transaction to act.

Everything here moves real money. Read the ledger model first.

The escrow ledger

Every contribution writes several ledger legs, each with its own reference so they can be told apart and so none of them can be written twice.

Leg Direction Reference suffix
Purchase debit Buyer → out _purchase
Platform fee Buyer → Super Admin the contribution id
Escrow hold In → Super Admin _escrow
Escrow release Super Admin → out _escrow_release
Payout to creator In → creator _release
Escrow refund Super Admin → out _escrow_refund
Refund to buyer In → buyer _refund

transaction.referenceId is unique across the whole platform. When every ICO leg used the bare contribution id, the escrow credit written at purchase permanently occupied that value and the release and refund rows could never be inserted — verification and rejection both died on a uniqueness error, leaving the contribution stuck in escrow with no way out.

If you are reconciling by hand, match on the contribution id prefix, not on an exact reference.

The escrow account is whichever account holds the Super Admin role. Its wallet in the offering's currency is created on demand. Without a Super Admin, purchases fail outright — see Install.

Fees the platform keeps

Two, both routed to the platform rather than destroyed:

  • The launch fee, charged once when a creator submits an offering. Its amount and currency come from the launch plan.
  • The contribution fee, a percentage of every purchase, charged on top of the contribution rather than deducted from it.

Both appear in the paying user's transaction history and in platform revenue. A plan priced at zero, or a fee percentage of zero, simply skips the charge.

Verifying a delivery

A contribution reaches your desk at VERIFICATION when the creator has sent tokens on-chain and recorded the hash. For a vesting contribution, that happens on the first tranche.

Verify, reject, or add and remove notes on a contribution

Verify is allowed only from VERIFICATION. It:

  1. Debits the escrow wallet for the contribution's value (amount × price).
  2. Credits the creator's wallet with the same figure.
  3. Sets the contribution to RELEASED.
  4. Emails and notifies both sides.

Only the hash's format is validated, and then only for ethereum, bsc, polygon, bitcoin and solana. On any other chain value, any string is accepted. Nothing queries a block explorer, confirms the amount, confirms the destination or confirms the transaction exists.

Verification is a human decision. Open the hash on a block explorer and check the amount and the destination address against the contribution before you click. Once you verify, the money is the creator's.

A vesting contribution is the sharpest version of this: verifying its first tranche releases the entire purchase amount while the rest of the schedule is still outstanding. There is no partial escrow release. See Vesting.

Rejecting a delivery

Reject is also allowed only from VERIFICATION. It does five things, and all five matter:

  1. Debits escrow and credits the buyer with the contribution's value.
  2. Sets the contribution to REJECTED, merging the rejection note into its record.
  3. Restores the tokens to the phase that sold them, so the allocation can be sold again.
  4. Recomputes the offering's participant count from live contributions.
  5. Cancels any vesting schedule behind the contribution, so the creator stops being told to send tranches for money that has gone back.

Reject when the hash does not check out, when the amount is wrong, or when the destination is not the address the buyer supplied.

Notes

save-note attaches an administrative note; remove-note clears it. Both are refused once a contribution is RELEASED.

A contribution's notes field is JSON carrying the purchase metadata every later screen and refund path reads — the phase name, the decimals, the raw token amount, the fee. Overwriting it with plain text used to destroy that record: the creator's release door threw on parsing it and every refund path silently skipped the contribution.

The current behaviour merges, so notes are safe. If you are editing rows by hand in the database, do not replace this column with free text.

Every way money leaves escrow

Path Trigger Who is paid
Verification You verify a delivery The creator
Rejection You reject a delivery The buyer
Soft-cap failure The hourly cron closes an offering below its soft cap Every outstanding contributor
Manual refund run Creator or admin calls the refund endpoint on a FAILED or CANCELLED offering Every outstanding contributor
Emergency cancel A Super Admin cancels a live offering Every outstanding contributor
Refund every outstanding contribution on a failed or cancelled offering
Check whether an offering is eligible for refunds

Neither of those two carries a permission key. They gate on who you are relative to the offering: the refund run accepts the offering's own creator or any administrator, and the eligibility view additionally accepts anybody holding a contribution in it.

The refund run is refused for any offering not in FAILED or CANCELLED. You cannot hand money back on a running sale — pause it, let it end, or cancel it.

All the refund paths share one implementation and one idempotency rule: the ledger is the authority, and one completed refund against a contribution id means that buyer has been paid. A contribution you already rejected is skipped by a later failure sweep rather than refunded again.

Refunds source the money from escrow before crediting the buyer. If no Super Admin exists, the credit still happens and is logged as unbalanced — the buyer is made whole out of the platform's own funds. That is a configuration fault to fix, not a behaviour to rely on.

Reconciling a stuck contribution

Work in this order.

  1. Read the status. PENDING means paid and undelivered — normal, and not something you act on. Only VERIFICATION rows are yours.

  2. Check the offering's status. An ACTIVE offering whose end date passed long ago means the cron is not running. Nothing settles without it; see Install.

  3. Check the ledger. Search the platform's transaction table for the contribution id as a reference prefix. The legs present tell you exactly how far the purchase got.

  4. Check for an existing refund. A completed REFUND leg against the contribution means the buyer has already been paid, and every refund door will now skip that row. If they are still asking, the money is in their wallet.

  5. Check the escrow wallet exists in the offering's currency on the Super Admin account. A missing escrow wallet is the one fault that produces plausible-looking transactions and an unbalanced ledger.