Docs menu: Fees and handle claims

Fees and handle claims

Status. Built and tested on a local validator: paying fees to a wallet, the vault's split, and claims for an X account with a signed permit. The X login has only been run with a stand-in provider, never against the real X API. Built to limit a stolen permit: it names one wallet, works once, and the Latch service signs it for at most five minutes. Nothing built limits a stolen signing key or a malicious admin: the vault accepts any maximum and any expiry up to 15 minutes ahead, so whoever holds the key can drain every X-account escrow at once, and the admin can replace the key instantly. A claim delay, a guardian, threshold signers, a cap and expiry of unclaimed funds are planned, not built. See X claims for setup.

Where fees come from

Every swap against the DAMM v2 pool pays a fee, set by the pool's fee scheduler and optional dynamic fee. Fees accrue on the position and are not compounded into liquidity. They are paid out when the position owner calls claim_position_fee. A permanently locked position still earns and can still claim fees; only withdrawing liquidity is blocked. Verified (Meteora docs).

Fees accrue in the pool's collect-fee mode. With a mode that collects both tokens, you receive some SOL and some of the launched token. With a quote-only mode you receive SOL only. Latch launches use the both-token mode, which is the one the local tests exercise. Quote-only mode with a single-sided pool has not been tried.

Split

Meteora keeps its protocol fee (20 percent of each trading fee in its current code) when the trade happens, so the fees a position earns are what is left. The vault splits each crank of those into a creator share (creator_bps, at most 95 percent) and a protocol share. The split is written at launch and cannot rise for the creator, only fall. This protects the protocol's minimum share. It does not stop the creator from pointing their share at another wallet. Anyone can call crank_fees, so no one needs to be trusted to run it, and a bot can do it on a schedule.

Two payout modes

  • Direct wallet. The creator share goes straight to the recipient wallet. You still trust the vault's upgrade key, Meteora, and the creator, who can point the recipient at another wallet at any time.
  • X-account escrow. The creator share is paid into token accounts owned by an Escrow account for that launch, and the launch records a numeric X user id. It can be released only with a permit from the claim signer. The launching wallet cannot collect it.

Claiming by X handle

Why the id and not the handle. Handles can be changed, sold or recycled. The permit binds to the numeric X user id returned by OAuth. The UI displays the current handle, but the chain stores the id.

The flow.

  1. The claimant opens the claim page and signs in with X (OAuth 2.0 with PKCE). The server reads the authenticated user id.
  2. The server checks that id against the launch's creator_x_id.
  3. The claimant connects a wallet. The server creates a permit and signs it with its ed25519 key. The exact bytes are in X claims.
  4. The claimant submits a transaction with two instructions. The first is the native Ed25519 program instruction that verifies the signature over the permit. The second is claim_creator_fees, which reads the instructions sysvar to confirm the verify instruction exists and matches, checks the expiry, the nonce and the signer public key stored in the vault's config, then pays out and increments the nonce.

Because the nonce increments, a stolen permit works once. Because the permit names the claimant wallet, an observer cannot reuse it for a different wallet. The five minute life of a permit is a rule the Latch service follows when it signs. The vault only checks that the expiry has not passed.

What you are trusting

The claim signer, and the admin who can replace it. A stolen signing key has no built-in limit. Whoever holds it signs their own permit with any expiry, the current nonce, their own wallet and the largest possible maximum, for every escrow, and the vault pays it out. If the key goes offline, claims stop. The only brake is set_claim_signer, which the admin can call instantly, and the admin can also point the vault at their own key.

Mitigation Effect Status
Permit names one claimant, one launch, one nonce A stolen permit works once, only for the wallet it names. Built
The service signs maximums equal to the escrow balance and expires permits in five minutes Limits what the honest service signs. The vault itself accepts any maximum and any expiry, so this does not limit a key holder. Built, off-chain only
Admin can replace the signing key (set_claim_signer) The way to react to a leak, once someone notices. Instant, with no next key and no timelock. Built
Claim delay window, guardian Large claims would show up on-chain first and could be paused. Planned
Threshold signers Require 2 of 3 independent keys. Planned
On-chain permit horizon and a cap The vault would refuse far-future expiries and large maximums. Planned
Unclaimed expiry After a long period the share would go back to a fallback. Planned

Who collects what

There are three kinds of launch, and the answer differs:

  • No vault. The launching wallet holds the position and is the only wallet that can collect. Losing that wallet loses the fees.
  • Vault. The vault holds the position. Anyone can trigger a collection, and the vault pays the creator's share to the recipient recorded on the launch and the rest to Latch. The recipient can be changed by the creator at any time.
  • Vault with an X account. A collection pays the creator's share into the launch's escrow. Only the owner of the named X account can release it, on the claim page. The launching wallet cannot.

Why not a trustless proof of an X account

X does not issue signatures that a Solana program can verify. A zero-knowledge proof of an OAuth session is an active research area and not production-ready for this use. Until it is, any "claim by social account" system, ours included, rests on a signer.