Token Distribution
In BuildToken Distribution lets an issuer put an allocation into every wallet an eligibility list names, at one fixed cost, without a payout system per campaign.
Every token distribution shares one Merkle-root eligibility check and one timelocked withdrawal path; how a recipient actually receives tokens diverges by family.
Token Distribution puts an allocation into as many wallets as an eligibility list names, at one fixed publishing cost whether that list holds ten recipients or ten thousand. Every claim checks against a single Merkle root rather than a stored per-address list. A seven-day timelock on owner withdrawals is the same across all three families.
A push distribution moves tokens the moment the sender distributes them, with no claim step for the recipient. A time-bound distribution flips that: each recipient claims their own full allocation once, self-service, only inside a fixed start and end window.
A vesting distribution initializes first, then pays claim after claim as the strategy pinned at that initialization unlocks more.
Why put an allocation in many hands without running a sale
After a token is issued, an issuer often needs to put units into many wallets at once. That covers rewarding the holders who already stayed, seeding a launch's early community, or paying out the allocations a subscription round already promised. Doing that as a sequence of individual transfers means paying gas for every one, keeping a private list of who has been paid, and reconciling that list against what the chain actually moved.
Token distribution replaces that private list with one published Merkle root: a single committed value that proves the whole recipient set and every allocation the moment the contract deploys. Publishing it costs the same whether the list names ten recipients or ten thousand, because the contract never stores the list itself, only the root a caller's proof is checked against. Asset Lifecycle names design, issue, created-paused, service, and retire as an instrument's five stages. Each distribution transfer runs as an ordinary movement through that same instrument's transfer path, the one issuance and every other servicing operation already write to. A private, off-platform list of who was owed what is the kind of separate record Asset Lifecycle's own seam-count argument warns against: a second ledger that can drift from the one the chain actually settled.
Why this runs on the token's own compliance path, not a separate payout system
The transfer a distribution pays out runs through the underlying token's own transfer-compliance modules. Those are the same modules that check every other transfer on that token, detailed under Controls and evidence. A payout system built beside the platform instead would need its own view of who may hold the token, a second copy of the eligibility rules the token's compliance modules already enforce. Any daylight between those two views is where a distribution could pay a wallet the token's own rules would have refused.
Nothing here needs a separate custodian or a second wallet holding funds in transit. A push distribution's sender holds the tokens until the moment they move, and a self-service distribution's contract holds them under the same eligibility check that already governs the token everywhere else. Whichever of the three families the issuer picks, the same eligibility rules decide where the tokens are allowed to land.
What Token Distribution is, and how the three families differ
Token Distribution lets you put an allocation into as many wallets as your eligibility list names, at one fixed publishing cost. Markets colloquially call this an airdrop, and the platform's contract families and API identifiers keep that word. What differs from one family to the next is who pays gas, and when the reward actually reaches a recipient's wallet.
A push distribution puts every transfer on the sender. The issuer calls distribute or batchDistribute, and tokens land in each wallet unasked. Reach for it when a reward must land on a fixed date, and the issuer is willing to cover every transfer's gas.
A time-bound distribution flips who pays and who acts. Each recipient calls claim themselves, once, inside a start and end window the issuer sets. Each recipient authorizes their claim. The recipient or a configured relayer pays its gas. A recipient list of any size costs the issuer the same amount to publish, because eligibility rests on a Merkle proof rather than a stored per-address list. Reach for it when recipients can cover their own gas and should self-serve inside a window you set, rather than wait for the issuer to push every transfer out one by one.
A vesting distribution spreads the reward's economic effect out over time, discouraging an immediate sell-off. A recipient first initializes their allocation, which starts a vesting clock but moves no tokens, then claims repeatedly as more of the allocation unlocks under a pluggable strategy, such as a linear schedule with a cliff. No separate lock-up contract is needed for any single recipient; the distribution itself carries the schedule.
Every family shares one recovery path. The owner can withdraw unclaimed tokens, but only by scheduling a withdrawal and waiting a fixed seven days, a wait the owner cannot shorten. The timelock delays owner withdrawals; the underlying token's transfer rules still apply. This shared design sits beside Primary OfferingA Primary Offering lets an issuer sell newly issued units once and resolve payment, allocation, and delivery or refunds as one on-chain outcome.Read the concept as the platform's other route for putting a token in a holder's hands, sold rather than distributed under a Merkle root.
Running a distribution day to day
Token distribution's three families divide the day-to-day operating work differently. Push distribution is operator-driven: the operator or a role-holding automation calls distribute or batchDistribute, moving tokens to each recipient without the recipient acting. Time-bound and vesting distributions are self-service, so the operator's job narrows to setting the claim window or the vesting strategy.
Each recipient on a self-service distribution calls claim or batchClaim themselves; the operator never moves a token on their behalf.
A push distribution enforces two limits on chain. It cannot double-pay the same Merkle index, and it cannot exceed a distribution cap when one is set (a cap of zero means uncapped). Both checks run inside distribute itself, so a batch that would violate either one fails before any tokens move. The cap is not fixed for life: the owner can raise or lower it later, and each distribution is checked against the running total at that moment.
A vesting distribution has an operator-visible step that push and time-bound skip: initialization. A recipient's index moves through two states worth tracking separately: not yet initialized, and initialized and vesting. An uninitialized index cannot be claimed at all, no matter how much time has passed, and initialization itself stops working once the distribution's own initialization deadline passes. Track which recipients have initialized separately from which have claimed, since initializing moves no tokens and is not itself a transfer.
A vesting index moves through exactly one initialization, any number of claims, then a fully claimed state; push and time-bound skip the initialization step entirely.
Recovering unclaimed tokens is the one lifecycle step every family shares, and it is deliberately two steps. An owner schedules a withdrawal, waits seven days, then executes it. The owner can cancel the schedule at any point before execution, and a rescheduled withdrawal waits the full seven days again. Only one withdrawal can be pending at a time, and no direct, one-call withdrawal exists.
Recovery is slow by design. The wait is the recipients' notice, and a cancelled schedule starts over from zero rather than resuming.
Watch a push distribution's cap and per-index claim state the way you would watch any batch payment run, for failed items rather than only completed ones. A time-bound distribution needs its window watched, since a claim outside the start and end time fails outright rather than queuing. The window is set when the distribution deploys and has no setter, so extending one means deploying a new distribution. A vesting distribution needs its initialization deadline tracked separately from its claims, since a recipient who never initializes in time never enters the vesting clock at all.
One base contract, three claim implementations
One abstract base contract underlies all three token distribution families and owns exactly two things: Merkle-root eligibility and the seven-day timelocked withdrawal. The root has no setter; a changed eligibility list needs an entirely new distribution contract, not an update to an existing one.
Everything about claiming diverges below that shared base. Each family plugs in its own claim-tracking behavior, and the tracker type is what actually distinguishes a push claim from a vesting claim at the storage level. A push distribution tracks claims with a bitmap, one bit per index, claimed or not, with no concept of a partial amount. Time-bound and vesting distributions both track a cumulative claimed amount per index instead. Time-bound spends that capacity on one full claim; vesting is the family that actually exercises it, claiming progressively.
| Behavior | Push | Time-bound | Vesting |
|---|---|---|---|
| Choose it when | A reward must land on a fixed date and the issuer covers every transfer's gas | Recipients can cover their own gas and should self-serve inside a window you set | The reward should unlock gradually rather than land all at once |
| Who moves tokens | The owner, calling distribute or batchDistribute | Each recipient, calling claim or batchClaim | Each recipient, calling claim or batchClaim |
| Claim step | None; claim and batchClaim always revert | One claim per index, full allocation | Initialize once per index, then claim repeatedly |
| Timing gate | None beyond the owner's own schedule | Only inside the start and end time | Initialize before the deadline; claim any time after |
| Claim tracking | Bitmap: claimed or not, no partial amount | Amount-based, used for one full claim | Amount-based, used for progressive claims |
| Unlock pace | Set by the owner's own distribution schedule | Full amount unlocks at the single claim | Set by the strategy pinned at initialization |
The three distribution contract families, compared where they diverge.
A vesting distribution's second divergence is strategy pinning. Calling initializeVesting for an index pins the strategy current at that moment into the index's own record, before any tokens move. Every later claim for that index recomputes against the pinned strategy, never the contract's current one. An owner can repoint future initializations at a new strategy, but no index already initialized ever notices the change. A linear vesting strategy fixes its cliff and total duration as constructor arguments at deployment, both immutable afterward. The allocation vests linearly across the full duration measured from your own initialization, but nothing is claimable until the cliff elapses; once it does, your first claim pays out everything the line has already reached.
Every distribution, in any family, is deployed as its own contract with a predictable address, so its identity is known before deployment. Deploying one needs the TOKEN_FACTORY_MODULE_ROLE at the system level, or the GOVERNANCE_ROLE on that specific token, a role grantA role grant turns an institution's segregation-of-duties policy into a check the ledger itself runs before every privileged call.Read the concept the access manager checks before the deployment call runs; it is not open to arbitrary callers.
The integration contract
On chain, the three token distribution families expose different verb sets, and calling the wrong one for a given distribution's family reverts rather than silently doing nothing. Push exposes distribute and batchDistribute, gated to the owner, and its claim and batchClaim always revert with a dedicated error (DALP-3018).
Time-bound and vesting both expose claim and batchClaim to any caller; vesting requires initializeVesting or batchInitializeVesting too, as a mandatory first call per index, before that index's claim will succeed.
A claim, a distribution, and an initialization all check against the same fixed Merkle root, using the exact leaf-encoding format the platform API reference specifies for an index, an account, and a total amount. The proof must match that format precisely, with no fallback path, and building the correct proof for a given entry is entirely your integration's responsibility.
Two caller-side limits shape how you submit. Every claim and initialization verifies the leaf against the caller's own address and pays that address, so integrations submit claims from the recipient's wallet rather than a service account. And batch calls cap at 100 entries in every family; a larger batch reverts before any entry processes.
A batch call's effect on token movement also differs by family. A push batchDistribute sends a separate transfer to each named recipient. A batchClaim on time-bound or vesting collapses several of the caller's own indices into one transfer.
Read a distribution's identity, its token, and its Merkle root from the platform's read model, which includes a discriminator distinguishing the three families. The platform API reference documents three discriminator values: push-airdrop, time-bound-airdrop, and vesting-airdrop. Cross-reference the per-recipient totals for what has actually moved. Vesting-only fields stay empty for push and time-bound entries.
Distinguish a failed eligibility check from an ineligible-right-now state before you surface an error to a caller. An index that has not yet initialized fails vesting's claim with DALP-3025, and a claim outside the active window fails time-bound's claim with DALP-3001 or DALP-3002, depending on which side of the window it falls. Neither of those is the condition a bad Merkle proof produces (DALP-3032), nor the one an already-claimed index produces (DALP-3030). Treat all four as separate cases in your own error handling, rather than collapsing them into one generic claim-failed message.
Controls and evidence
A distribution's eligibility decision happens entirely off chain, as a control function. Whoever builds the Merkle tree decides who is on the recipient list and for how much; the contract enforces only that a claim, a distribution, or an initialization matches the committed root.
The audit question for a distribution is who built that tree, from what source list, and under what approval, not what the contract technically allows, because the contract allows anything the tree contains.
The transfer runs through the underlying token's own transfer-compliance modulesTransfer-Path Compliance enforces a regulated token's rules inside the on-chain transfer itself, so a movement that fails any rule reverts and never settles.Read the concept, the same modules that check every other transfer on that token by evaluating each configured rule before balances change and reverting if any rule fails.
Evidence is on chain and per distribution, across all three families. Creation, every transfer, whether a push distribution or a self-service claim, every vesting initialization, and every withdrawal-schedule step each emits its own event. An auditor reconstructs exactly which index paid whom and when, and through which of the three paths: a push send, a time-bound claim, or a vesting initialization followed later by one or more claims. The chain records execution. Keep the recipient list and its approval evidence separately to explain how the Merkle root was chosen.
A push distribution and a self-service claim carry different accountability even though both move the same tokens. A push distribution is a step the operator, or an authorized automation, took on the recipient's behalf. A claim is a step the recipient took themselves. The event trail preserves that distinction rather than flattening both into one generic transfer record.
Frequently asked questions
What happens when a push distribution misses a recipient?
The owner can still distribute to that index later, because a push distribution has no claim window and no deadline of its own. The recipient cannot self-serve in the meantime: a claim on a push contract always reverts. The index stays payable until the owner distributes it, the distribution cap would be exceeded, or the owner withdraws the remaining balance through the timelocked path.
What happens if I never initialize my vesting allocation?
Nothing unlocks, ever. The vesting clock starts only when initialization runs for your index, and the contract refuses that call once the distribution's initialization deadline passes, so a late attempt reverts. Your allocation then sits in the contract as unclaimed balance, recoverable by the owner through the seven-day timelocked withdrawal. Initialize before the deadline even when you plan to claim much later.
Does my vesting schedule run from deployment or from my own initialization?
From your own initialization. The contract records the timestamp of your initialization, and the strategy measures the cliff and vesting duration from that moment, so two recipients who initialize a week apart also finish a week apart. Waiting to initialize does not bank vested time; it delays the entire schedule, and the initialization deadline caps how long you can wait.
Can I claim while the cliff is still running?
No; the call reverts rather than paying zero. Under a linear strategy, nothing is claimable until the cliff duration has passed since your initialization, and the contract rejects a claim whose computed claimable amount is zero. Once the cliff passes, the first claim pays everything vested since initialization in one transfer, and later claims pay only what unlocked since the previous one.
Can someone else claim my allocation for me?
Not the claim itself; only the gas payment can move. The platform's meta-transaction support lets a relayer submit the transaction and pay the gas, but the recipient still authorizes it and still receives the tokens. When recipients cannot transact at all, even through a relayer, a push distribution is the family built for that.
Can the owner withdraw tokens while claims are still open?
Yes. Scheduling a withdrawal is not blocked by an open claim window or a running vesting schedule; the seven-day wait is the notice recipients get, and the scheduled time is readable on chain. Execution then empties the contract, after which a claim has nothing left to pay and fails. Fund the contract for the full allocation, and withdraw only once the window or deadline you set has passed.
Corporate Action
A Corporate Action pays a coupon, a dividend, or a matured redemption straight to token holders, turning an issuer's announced terms into an on-chain payout.
Trading Venue
A Trading Venue lets a tenant run its own market for a tokenized asset after issuance. The venue contract never gains custodian power over what trades on it.