Skip to main content
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.
A Token-2022 base mint created by 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_auth set, that key is the mint’s withdraw_withheld_authority from creation. Call Token-2022’s own WithdrawWithheldTokensFromAccounts / WithdrawWithheldTokensFromMint directly; LaunchLab has no instruction for this and never did.
  • transfer_fee_config_authority timing is unchanged. It is still the launch authority PDA until graduation, and still moves to transfer_fee_extension_auth in MigrateToCpswap. The fee rate cannot be changed mid-launch.
  • Set transfer_fee_extension_auth before launching. When it is Pubkey::default() at mint creation, the withdraw authority falls back to the authority PDA — 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.
  • MigrateToCpswap is 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:
  1. At InitializeWithToken2022, for withdraw_withheld_authority.
  2. At MigrateToCpswap, for transfer_fee_config_authority — and for withdraw_withheld_authority only when the PDA still holds it.
Rotate the field through 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’s SetAuthority 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_RATE is still 500 (5%, denominator 10_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, same remaining_accounts indices, same two token programs, no arguments.
  • InitializeWithToken2022’s interface. Same accounts, same TransferFeeExtensionParams, same NoSupportExtension rejection for anything outside MetadataPointer and TransferFeeConfig.
  • Quote-side Token-2022 handling. Unchanged from 2026-08-24.
  • Error codes. 60006023 are unchanged; this release adds none.
  • Account layouts and the IDL. Unchanged. PlatformConfig.transfer_fee_extension_auth keeps 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/instructionsMigrateToCpswap gains a “Token-2022 transfer-fee authority handover” block; Initialize postconditions 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.