a latch your
wallet key
can't lift.

If AI or a quantum computer ever learns to crack Solana wallet keys, whoever cracks yours can take everything in it. Latch puts a second lock on this coin that a cracked key can't open. Turn it on, and your tokens stay put even if your wallet key doesn't.

optionaloff until you turn it on
buyingnever changes
one codeper sell or send

program 8jAukWNHrzpaFe3cqMCnNF2aCJLWpHdLodBxFPmhuAmPdevnet · not yet immutable

LATCH · REV 2026-10-08 · DEVNETdrag to turn it · click to open it

for the technical · the precise version

a hash-based second factor, enforced by the token itself

Latch is a Token-2022 transfer-hook program. A holder opts in by committing, to a PDA seeded by their token account, the Merkle root of 2h Winternitz one-time public keys (W-OTS, w = 16, SHA-256, 67 chains; h = 10 by default). From then on, Token-2022's mid-transfer CPI into the hook requires a single-use authorization whose digest, SHA-256("qlh:xfer" ‖ mint ‖ source ‖ destination ‖ amount ‖ nonce), is recomputed from the live transfer and consumed on use. Authority over a latched balance therefore reduces to the one-wayness and second-preimage resistance of SHA-256, not to the discrete-log hardness of Ed25519. An ECDLP break, by Shor or by an undiscovered classical algorithm, yields signatures but not transfers.

Authorization
W-OTS signature, 2,144 B, staged in a scratch PDA and verified on chain against the committed root: at most 1,005 SHA-256 evaluations plus an h-level Merkle path, about 250k CU. Ed25519 remains a co-signer, so the scheme is hybrid, not a replacement.
Binding
Digest fixes mint, source, destination token account, amount and a monotonic per-account nonce. Authorizations are single use, valid only for the latest nonce, and expire after 750 slots.
State discipline
Leaves are consumed in strictly increasing order, with forward skips allowed so a leaf exposed by a failed attempt is never re-signed. The final leaf is reserved for Unlock and Rotate, the nonce survives re-registration, and re-registering a prior root is refused.
Key lifecycle
Rotate re-keys atomically under a signature over SHA-256("qlh:rotate" ‖ mint ‖ source ‖ root′ ‖ h′ ‖ nonce), with no unlatched interval. Unlock is itself W-OTS-authorized and refunds the scratch and auth rent.
Robustness
Every PDA is created with a top-up, allocate and assign path, so lamport pre-funding cannot block an account or a mint's extra-account-meta list. Execute rejects calls outside a live transfer via the source account's transferring flag.
Margins and limits
Grover's quadratic speed-up leaves about 2128 work against 256-bit preimages. Outside the model: Burn is not hooked; a sell binds the pool vault, not the swap's output account, so the authorization is copyable until it lands (private bundles close this); the mint's hook authority sits with Meteora's DBC pool-authority PDA; the program's upgrade authority is to be revoked on mainnet.

This is the reviewed build, deployed on devnet at the address above and run against every finding of the review there. The pre-review program was closed.

the problem

on solana, your address is your key

On 7 October, Ethereum researcher Justin Drake warned that AI might find a shortcut for working out a wallet's private key from its public key, in months rather than the decades quantum computers were expected to take. Nobody has done it yet. But if it happens, every wallet whose public key is known can be emptied.

  1. Ethereum can hide. An Ethereum address is a fingerprint of the key, not the key itself. Drake's advice, "bunker mode", is to move funds to a fresh address that has never sent anything, so the key stays hidden.
  2. Solana can't. A Solana address is the public key. Every wallet has shown its key from the moment it existed, so there is nowhere to hide it.
  3. So Latch makes the key not enough. Instead of hiding the key, the coin itself demands a second proof that has nothing to do with the key, built only on hashing, which neither AI shortcuts nor quantum computers are known to break.
1 · body2 · shackle3 · cylinder

how it works

a lock in three parts

1 · your codes. Turning the latch on makes 1,024 single-use codes on your device. Only a fingerprint of them goes on chain, so nobody can work the codes out from it.
2 · one code per move. Every sell or send uses one code, made for that exact amount and that exact destination. A code works once and never again.
3 · the coin checks. On every transfer, the coin asks one question: is this account latched? If it is, no matching code means no transfer.

latch off the default

Nothing is different. Buy, sell and send like any other coin. Nobody can turn the latch on for you.

latch on

Selling or sending takes one code, which this site supplies for you along with one wallet approval. Buying never needs a code. Nobody else can move your tokens, even with your wallet key.

live · in your browser

watch a code get made

Type a transfer and sign it with a one-time key. Your browser just made 1,024 of them with the same code the holder app uses; nothing leaves this page. Each of the 67 chains is SHA-256 applied over and over: the signer walks up to the digit of the transfer's digest, the checker walks the rest of the way, and every chain has to land on the key the fingerprint on chain commits to.

digest

scroll the picture sideways to see all 67 chains and the path to the root.

Then change the amount by one. The signed code stays put and the picture shows what a thief would need: every red chain has to run backwards, which means inverting SHA-256.

the attack

someone has your wallet key. now what?

Say an AI shortcut, a quantum computer or a plain leak hands someone your wallet key. They can sign anything as you. Play the thief: below are the moves, run against the real program on devnet.

you hold the key for 94vgMa…cdze, the wallet from the run. reading its latch…

Each try is built as the real transaction, signed as that wallet, and run by devnet itself with signature checks off. Nothing is sent.

  • Connect the wallet on this site to sellblockedIts codes aren't in the wallet. They live on the owner's device and in their backup, so the site has nothing to sign with.nothing to try
  • Send its tokens to your own walletblockedThe coin checks every transfer. No code, no transfer, whatever app or script you use.
  • Sell them into the poolblockedA sell is a transfer into the pool, so it meets the same check.
  • Turn the latch offblockedTurning it off takes one of the owner's codes too.
  • Latch it again with codes of your ownblockedLatching over a latch is refused, and replacing codes takes a current code.
  • Take the wallet's SOLpossibleOnly this coin is latched. Nothing a coin can do protects SOL; that needs Solana itself to change.
  • Burn the latched tokenspossibleThe check runs on transfers, not burns. You gain nothing, but the tokens are gone.
control. The same send from a holder with no latch, to show the coin isn't just refusing everything.

If you think your key leaked: send, don't sell. A sale pays SOL into your wallet, and whoever has your key can take it from there. Move the latched tokens to a fresh wallet first: the send is bound to that wallet, so nobody can redirect it.

but couldn't AI crack the codes too?

  1. The danger isn't guessing. Nobody can guess a wallet key, AI or not: there are more possible keys than atoms in the universe. The worry is a mathematical shortcut. A wallet's public key is built from its private key with curve maths that has hidden structure, and a clever enough method, quantum or AI-found, could run that structure backwards.
  2. The codes are not small. Each code is 2,144 random-looking bytes, made from a 256-bit secret. What sits on chain is only a fingerprint of them, made with SHA-256 hashing.
  3. Hashing has no structure to exploit. A hash scrambles its input with no maths linking the output back to it. The best known quantum trick only halves the work, which still leaves more tries than could ever be done. That is why the official post-quantum standards include hash-based signatures as the most conservative choice, and why Bitcoin mining runs on the same SHA-256. If SHA-256 fell, far more than this coin would break.
  4. The weak spot is your backup, not the chain. Nothing secret goes on chain, so nobody can attack your codes from there. They can only be taken from your backup: your 24 recovery words, or your backup file together with its passphrase. Keep the words on paper and the file somewhere private.

Two things the latch can't fix: someone who gets your recovery words, or your device or backup file plus the passphrase, has your codes too, and the latch has to be on before keys can be cracked. After that, someone who can forge your key could turn on a latch of their own first.

use it · devnet

your latch

Connect a wallet to latch, send, sell and lift from this page. Or look any wallet up without connecting.

Your seed is generated and used only on this page. It is kept in this browser's storage, sealed with your passphrase, and backed up the way you choose: 24 words you write down, or a backup file. The server builds unsigned transactions from public data and never sees a key. Before your wallet is asked, this page checks each one against what you typed and refuses anything else; every transaction is signed by your own wallet. A browser is a weaker home for a seed than an encrypted file on your own disk, so large balances are better served by the command line. Try the run's wallet without connecting: .

proof · devnet · 2026-10-08 · 16:30 mdt

the run

The whole flow, done for real on Solana's test network: launch the coin, buy, sell, turn the latch on, try to sell without a code (refused), then sell with one. Every line opens in Solana Explorer.

  1. Create the curve and the mint, hook attached3ZZBQ2…Xbdg
  2. Set up the hook's account list for the mint5G5frX…2WBJ
  3. Buy with 0.05 SOL. 1,177,185 tokens land in the walletPvPtWv…SyuG
  4. Sell a fifth with the latch off. The coin lets it throughTZkYTJ…U8V3
  5. Turn the latch on. The program logs latch on: 256 one-time signatures registered3cXkwk…rPBg
  6. Sell a tenth with no code. Refused by the coin, error 0x64, NotAuthorizedno transaction
  7. Upload the code, part 1 of 32h1jpy…TyT2
  8. Part 2 of 32TwP9c…M2Sx
  9. Part 3 of 32hLVeW…YqHR
  10. The coin checks the code and logs transfer authorized with one-time key 02QQdjY…FNFX
  11. Sell the same tenth with the code. It goes through, and the code is used up4UnXhK…nnfG
  12. Another sell from the command line: three uploads, then authorized with one-time key 14yAQHY…rQ8e
  13. and the sale itselfyx8PBG…f5Fk
Mint DS5PqB…o4M1, pool 8R2dFn…kUmw, latch account dJGitC…Ytmi. The wallet is still latched; the lookup above reads it live. Every attack from the security review was also replayed against this program on devnet and refused.

details

good to know

Only this coin
The latch protects this coin's balance. Your SOL and other tokens are as safe or unsafe as they always were.
Where it trades
It trades wherever hook coins trade, like its own pool and this site. Some swap buttons and aggregators don't handle hook coins at all, latched or not.
Keep your backup
Lose this browser's copy and your backup (your 24 words, or your backup file and its passphrase), and a latched balance can never move again. There is no recovery, because a recovery path would be a way around the lock.
Codes run out, and renew
You get 1,024 codes. When they run low, renew to a fresh set without ever turning the latch off. The last code is always kept back so you can never lock yourself in.
A sell is open for seconds
A code for a send names the exact wallet, so it can't be redirected. A sell goes to the pool, so in the few seconds between your code going up and your sell landing, someone who can forge your key could use that code to sell the same amount themselves. A code also expires after about five minutes. On mainnet, sells will go out as one private bundle so the code is never visible early.
Meteora is trusted
The coin launches on Meteora, whose program holds the coin's hook setting. Nothing in it can change the hook today, and mint and freeze powers are revoked, but Meteora can upgrade its own program.
the technical version

how a latched transfer clears

  1. SeedGenerated on the holder's machine and sealed there, under Windows DPAPI or AES-256-GCM with a passphrase. It never touches the chain.
  2. One-time keys1,024 of them derive from the seed, each a set of 67 hash chains. The holder registers only the Merkle root of their public ends, 32 bytes.
  3. SignatureMint, source account, destination, amount and the account's nonce are hashed into one digest. The next unused key signs it by walking its chains part way, which takes 2,144 bytes to write down. The client uploads that in three transactions.
  4. AuthorizeThe program walks each chain the rest of the way, hashes the ends, checks the Merkle path to the registered root, and stores the digest as a single-use authorization. At most 1,005 SHA-256 calls, about 250k compute units.
  5. TransferToken-2022 calls the hook in the middle of the transfer. The hook recomputes the digest from the real accounts and amount, compares it to the stored one, and burns the authorization. A different amount, a different destination, or a second use all fail. Unlatching goes through the same verification, so a forged wallet signature cannot simply lift the latch.

the signature scheme

Scheme
Winternitz one-time signature, w = 16, over SHA-256
Chains
64 message chunks and 3 checksum chunks, 67 in all, each 15 steps long
Signature size
2,144 bytes
Keys per registration
1,024 by default, up to 65,536 at height 16
Replay
Keys are consumed strictly in order on chain, and each authorization is burned when the transfer uses it

accounts the program keeps

AccountSeeded byHolds
LatchToken accountOwner, Merkle root, height, next leaf, nonce
AuthToken accountOne pending digest and nonce, single use
ScratchToken accountSignature upload buffer
Extra metasMintTells Token-2022 to hand the latch and auth accounts to the hook

what a holder runs

# Is my account latched, how many keys remain
qlh status --mint MINT

# Drop the latch: 1,024 one-time signatures
qlh lock --mint MINT

# Send or sell: authorizes first when latched
qlh send --mint MINT --to WALLET --amount N
qlh sell --mint MINT --pool POOL --amount N

# Buying needs nothing special
qlh buy --mint MINT --pool POOL --sol X

# Lift the latch: spends one key
qlh unlock --mint MINT

The client reads the live key index and nonce from the chain before every signature, so a stale local file cannot burn a key. Flags: --keypair, --rpc, --program, or the QLH_KEYPAIR, QLH_RPC and QLH_PROGRAM variables.

log

what has happened so far

2026-10-07
Started the evening Justin Drake posted about bunker mode. Wrote the program in Rust on the SPL transfer-hook interface and the signature scheme twice, once in Rust and once in Node, with shared test vectors. Built with Solana platform-tools v1.54 in WSL and deployed to devnet as 8PM15GCCpaUhV2i3XLnAf9CCfMx6LcHzjP75i3fPWRW5. The seven-step test passed first run: latched transfer rejected, wrong amount rejected, replay rejected, unlatch with a one-time key. Then the holder client with the sealed seed. The curve rehearsal needed a change to how the hook's metas are initialised, because a Meteora launch hands the mint authority to the pool.
2026-10-08
Every devnet faucet was dry, from two IPs, and the deployer wallet had 0.356 SOL against about 0.6 needed. So I closed the 10-07 program to get its rent back and redeployed the rebuilt binary under a new id, 3SEqEuTv7zgWTLudXo6fnRM1ZJZAhWH7FUAfz6HwVjud. The old id is dead. The seven-step test passed again, then the curve rehearsal above, after fixing one thing in the client: the decoded pool state for a hook pool does not expose its token vault, so the client derives it. The site went up the same day, got its name and this look that evening, and then became the holder app: connect a wallet and latch, send, sell or lift from the page, with the seed generated and sealed in the browser and the server only building unsigned transactions. The whole flow ran on devnet from the page before it was called done. Then an adversarial review of the program before mainnet. It found one critical bug: anyone could send a few hundred thousand lamports to a holder's program accounts before they were created and block them forever, freezing that holder's tokens, or do the same to a new mint and stop all its transfers. It also found that a transfer could spend the last one-time key, and that a key exposed by a failed attempt could end up signing twice. All of it is fixed, a rotate instruction was added so keys can be renewed without unlatching, and every attack from the review now fails in a regression test on a local copy of devnet. That evening a faucet came back, so the hardened build went to devnet as 8jAukWNHrzpaFe3cqMCnNF2aCJLWpHdLodBxFPmhuAmP, the review's attacks were replayed against it there and all refused, the launch rehearsal ran again (the run above), and the pre-review program was closed. Late that night came a review of the site itself, treating its own server as the attacker. The page now checks every transaction against what you typed before your wallet is asked, shows the destination it worked out itself when you unseal your key, and keeps a permanent record of which one-time keys it has used, even across tabs and re-imported backups. The server stopped falling over on malformed requests, buys and sells got a price floor, and the whole flow ran again on devnet from the page, including a simulated lying server, which it refused.

build

Program
Native Rust, spl-transfer-hook-interface, 125,864 bytes
Toolchain
Rust 1.93, Solana CLI 3.0.15, platform-tools v1.54, built in WSL Ubuntu 24.04
Client
Node 24. Keys, signing, Merkle tree, the Meteora launch and sell path, the holder command line
Upgrade authority
Still the deployer wallet on devnet. The mainnet program gets its authority burned before any coin uses it, otherwise whoever holds that key could ship a hook that lets everything through
Not done
Mainnet deploy, about 0.6 SOL of rent. Burning the authority. The coin itself, which has to launch on a Meteora curve because pump.fun and LaunchLab cannot take a custom hook program

passphrase

recovery words