This entry covers an upcoming LaunchLab program update. It was verified against the local release branch before deployment. Confirm the deployed program before relying on pre-graduation withheld-fee withdrawal.
InitializeWithToken2022 can carry a TransferFeeConfig. That extension has two authorities: transfer_fee_config_authority, which changes the fee rate and maximum fee, and withdraw_withheld_authority, which withdraws the fees Token-2022 withholds on token accounts.
Until this release the program put the launch authority PDA on both of them at mint creation and handed both to PlatformConfig.transfer_fee_extension_auth at graduation. The launchpad program has no withdraw-withheld or harvest instruction, so for the whole bonding-curve phase nobody could withdraw the withheld balance — the only key that could was a PDA with no instruction to sign with it.
This release writes transfer_fee_extension_auth directly into withdraw_withheld_authority at mint creation, so the platform can sweep withheld fees from the first trade. MigrateToCpswap gains a guard so it only reassigns that authority when the PDA is still the one holding it, which keeps graduation working for mints from both generations.
Nothing else changed. No account grew or shrank, no instruction gained or lost an account, no argument changed, and no error code moved.
TL;DR for integrators
- Withheld transfer fees are withdrawable during the launch. On a new Token-2022 launch whose platform has
transfer_fee_extension_authset, that key is the mint’swithdraw_withheld_authorityfrom creation. Call Token-2022’s ownWithdrawWithheldTokensFromAccounts/WithdrawWithheldTokensFromMintdirectly; LaunchLab has no instruction for this and never did. transfer_fee_config_authoritytiming is unchanged. It is still the launchauthorityPDA until graduation, and still moves totransfer_fee_extension_authinMigrateToCpswap. The fee rate cannot be changed mid-launch.- Set
transfer_fee_extension_authbefore launching. When it isPubkey::default()at mint creation, the withdraw authority falls back to theauthorityPDA — the old behavior. Setting the field afterwards still recovers the authority at graduation, but the withheld balance is stranded until then. - Do not rotate the field mid-launch. The two authorities are read at two different moments, so a value that changes in between leaves them on different keys. Details in Rotation splits the two authorities.
MigrateToCpswapis unchanged for callers. Same accounts, same arguments, same errors. The new guard is internal; without it, migration of a new-generation mint would revert inside Token-2022 because the PDA can no longer sign away an authority it does not hold.- Existing launches are unaffected. Mints already on-chain keep the PDA on both authorities and still get both handed over at graduation.
- No IDL refresh is required. No layouts, accounts, arguments, or error codes changed.
Who holds what, and when
Both handovers still sit behind the same outer condition they always did: the base mint must carry
TransferFeeConfig and transfer_fee_extension_auth must be non-default. A platform that never sets the field keeps both authorities on the authority PDA forever — the fee rate can never be changed and the withheld balance can never be withdrawn.
Rotation splits the two authorities
transfer_fee_extension_auth is read twice per launch, at two moments that can be days apart:
- At
InitializeWithToken2022, forwithdraw_withheld_authority. - At
MigrateToCpswap, fortransfer_fee_config_authority— and forwithdraw_withheld_authorityonly when the PDA still holds it.
UpdatePlatformConfig in between and the two authorities land on different keys: the withdraw side keeps the key that was configured at creation, because the PDA no longer holds it and migration skips that handover, while the fee-config side goes to the new key. Neither call fails; the split is silent. Rotate between launches, or reconcile the keys afterwards through Token-2022 directly with the old key signing.
Why the guard is required, not just defensive
Token-2022’sSetAuthority requires the current authority to sign. Under the new creation rule the launch authority PDA is not the withdraw-withheld authority on a new mint, so the unconditional CPI the program used to make would fail — and because it sits inside MigrateToCpswap, that failure would have blocked graduation for every Token-2022 launch with a transfer fee on a platform that had configured the field. The two changes only work as a pair.
What did not change
- Transfer-fee math and accounting.
MAX_TRANSFER_FEE_RATEis still500(5%, denominator10_000), the fee is still priced into the curve the same way, and the withheld balance still accrues on the token accounts Token-2022 puts it on. MigrateToCpswap’s interface. Same account list, sameremaining_accountsindices, same two token programs, no arguments.InitializeWithToken2022’s interface. Same accounts, sameTransferFeeExtensionParams, sameNoSupportExtensionrejection for anything outsideMetadataPointerandTransferFeeConfig.- Quote-side Token-2022 handling. Unchanged from 2026-08-24.
- Error codes.
6000–6023are unchanged; this release adds none. - Account layouts and the IDL. Unchanged.
PlatformConfig.transfer_fee_extension_authkeeps its offset and its type; only when the program reads it changed.
Pages updated
products/launchlab/platform-config— new “Token-2022 transfer-fee authorities” section covering both authorities, both handover points, and the rotation trap; layout comment and pitfalls list corrected.products/launchlab/instructions—MigrateToCpswapgains a “Token-2022 transfer-fee authority handover” block;Initializepostconditions record the new mint-creation authorities.products/launchlab/accounts— authority-PDA role list and the base-mint section note which transfer-fee authorities the PDA actually holds.reference/token-2022-support— LaunchLab base-mint entry states who holds the transfer-fee authorities and when.

