Glacis Airlift
Through Lazer I built the Solana side of Glacis Labs' Airlift bridge, with one TypeScript SDK over Wormhole NTT and LayerZero OFT, fee quotes read from the chain, and the docs.
- Role
- Owned the Solana integration layer
- When
- Jun–Sep 2025
- Client
- Glacis Labs, via Lazer Technologies
- Stack
- TypeScript, Rust, Anchor 0.31, Solana web3.js, SPL Token + Token-2022, Wormhole NTT, and 4 more
- Status
- On mainnet
Context
Airlift is Glacis Labs' cross-chain token bridge. Someone holding a token on Solana can send it to an EVM chain such as Ethereum, Base or Arbitrum. Airlift wraps the underlying bridge protocol, takes a configurable fee, and routes the transfer in one atomic transaction.
The EVM side already existed. I joined through Lazer Technologies in June 2025 to do the Solana side, which meant getting it to work for real tokens and getting it ready for production.
When I started, only part of it worked. Most tokens couldn't be sent, and the fee quotes didn't match what transfers actually cost. There was no single interface over the two bridge standards, no pipeline for token configs, no quote API and no documentation.
What I built
Most of the work was an SDK. Wormhole NTT and LayerZero OFT share almost nothing at the call level, so I built an AirliftClient with one quote() and one send(). It reads each token's config to decide which protocol to use. I packaged it as a standalone TypeScript package and took every hardcoded keypair out of it.
Around the SDK I built:
- Transaction assembly with Address Lookup Tables, so the larger transfers fit in Solana's 1,232-byte limit.
- Quotes read from the chain, using the on-chain quoter's delivery price for NTT and LayerZero's own quote with the real message options for OFT. On the mainnet transfers we checked, the quoted fee matched the executed fee to the lamport.
- Amount handling across decimals. Solana mints usually carry fewer decimals than their EVM counterparts, and each protocol scales amounts its own way, so I normalized to the lowest shared precision on both paths and added the trimmed remainder to the fee.
- One config schema for a token under either standard, scrapers that read protocol state from the chain, and bulk scripts that register tokens on-chain.
- The Solana path in the backend quote service that LI.FI calls, matching the EVM path.
- The Docusaurus docs: architecture, the SDK reference, adding tokens, configuring fees and troubleshooting.
In the Anchor program itself I added the NTT integration, SPL Token-2022 support across the send path, and the fee-configuration logic.
Fitting a bridge transfer into 1,232 bytes
Move account keys into the lookup table and watch the size fall.
1,316 B
84 B over the v0 limit: this transaction fails
33 keys in the transaction · 0 in the lookup table
- Signature 65 B
- Header 4 B
- Account keys 1,057 B
- Blockhash 32 B
- Instructions 157 B
- Lookup table 1 B
In the transaction32 B per key · 33
- Sender (fee payer)Signer32 B: Signers must stay in the transaction
- Compute budget programProgram32 B: Invoked programs must stay in the transaction
- Bridge programProgram32 B: Invoked programs must stay in the transaction
- Sender token accountUnique32 B: Unique to this transfer, so no shared table holds it
- Outbound message accountUnique32 B: Unique to this transfer, so no shared table holds it
Address lookup table1 B per index · 0
Empty. The first key you move costs more than it saves: the transaction also has to name the table.
Before: 1,316 B with every key in the transaction. After: 482 B with all 28 shared program accounts in one lookup table. The quote matched what the transfer actually cost, to the lamport.
Legacy and v0 transactions are still capped at 1,232 bytes. The v1 format, on mainnet since Sept 15, 2026, raised the cap to 4,096 and doesn’t use lookup tables. Airlift shipped on v0, with Address Lookup Tables, in 2025.
Source: solana.com: larger transaction sizes · checked 2026-09-29
Illustrative, computed from the Solana wire format.
Architecture
- LI.FI or a front end asks the Airlift quote API for a price.
- The quote service calls the SDK's
quote(). The SDK reads the token's config and picks NTT or OFT. - The SDK prices the transfer from the chain, with the NTT quoter or with LayerZero's quote and the real message options.
send()assembles a v0 transaction that references the token's lookup tables, so it fits the size limit.- The Anchor program takes the Airlift fee and routes the tokens to Wormhole NTT or LayerZero OFT in the same transaction.
- The destination EVM chain receives the tokens.
Decisions
Callers don't choose a protocol. The client reads it from the token's config, so a partner writes one integration that covers both standards, and every token needs a config before it can move.
Lookup tables
Airlift takes its fee and routes the transfer in one atomic transaction, so splitting a big transfer into two transactions wasn't possible. Every account a Solana transaction touches costs 32 bytes in its account list, and a lookup table replaces each one with a one-byte index. I built a factory that packs the program accounts every transfer needs into shared tables, dropped an instruction the transfer didn't need, and compiled v0 transactions against several tables at once.
v0 limit 1,232 B
oversized LayerZero transfer ~1,289 B
same transfer, lookup tables ~1,033 BQuotes
A hardcoded fee is wrong as soon as relay costs move, so quote() reads the price from the chain every time. Quotes only need a public key, which made it safe for a front end or an API to price a transfer and let me take every secret out of the SDK. Credentials come from the environment.
What went wrong
The larger LayerZero transfers were failing outright, because they referenced too many program accounts to fit in 1,232 bytes. Moving those accounts into the lookup tables above fixed it.
The NTT fee quoter for a token can't be found from the token's manager program, and there's no registry for it. I recovered it by parsing relay requests out of the manager's historical transaction logs, and scraped the rest from Wormhole's public explorer data.
Registering tokens in bulk ran into RPC throttling, so the scripts retry at a limited rate.
Since then
Legacy and v0 transactions are still capped at 1,232 bytes. Solana's v1 format, live on mainnet since September 15, 2026, raised the cap to 4,096 bytes, and v1 doesn't use lookup tables. Airlift shipped on v0 with lookup tables in 2025. You can move account keys into a lookup table yourself in the 1,232-bytes demo.
Screenshots

How AirLift is described by Glacis. Image: Glacis Labs.
My part
Other engineers wrote most of the core Anchor program. My changes there were the Wormhole NTT integration, Token-2022 support and the fee logic, about 330 lines. I owned the layer above it, meaning the SDK, token configs, quoting, the quote API and the docs. The instruction-introspection design that keeps LayerZero sends within Solana's call-depth limit was already in the program, and I built the SDK and transaction assembly around it. Glacis Labs now markets the product as ZeroDelta.
Numbers
| Figure | What it measures |
|---|---|
| 2 | bridge standards behind one interface: Wormhole NTT and LayerZero OFT (Glacis public docs) |
| ~100 / 38 | token configs written or generated / tokens registered on-chain with managed fees |
| 13+ | destination EVM chains mapped across three chain-ID systems |
| 9+ | mainnet transfers verified across both protocols, two of them re-verified independently on Sept 5, 2025 |
| 1,232 B | the v0 transaction size limit Airlift shipped against (the v1 format raised it to 4,096 B in September 2026) (solana.com) |
| ~1,289 B → ~1,033 B | size of an oversized LayerZero transfer before and after lookup-table compression |
| ~300 → ~90 | lines in the Solana quote service after it delegated to the SDK |
Links
Stack: TypeScript, Rust, Anchor 0.31, Solana web3.js, SPL Token + Token-2022, Wormhole NTT, LayerZero OFT, Metaplex Umi, Helius, Docusaurus
