Bridge
In from Solana, out to Solana
The bridge moves tokens between the HELIX standard and Solana's token programs, one for one, in both directions. What goes in sits in a vault the program owns; what comes out is minted against it. There is no bridge fee: only the network fee and, the first time a token crosses, the rent of the accounts it needs.
register_wrapper(once per mint, by whoever bridges it first) creates the wrapper, its HELIX mint and the vault, which is the wrapper's associated token account. The HELIX mint's name, symbol and uri are read on chain from the token's own metadata (its Token-2022 metadata extension or its Metaplex metadata account), never typed in, so nobody can register USDC under another name. A token with neither gets “Bridged token”.wrap(amount)moves the tokens into the vault withTransferCheckedand mints, on HELIX, exactly what the vault received (a Token-2022 transfer fee is taken before it arrives).unwrap(amount)burns the HELIX tokens and pays the originals back from the vault, signed by the wrapper.
A wrapped HELIX mint has no hook, no freeze authority and no metadata authority; its mint authority is the wrapper, which signs nothing outsidewrap. Anyone can open a pool for it with create_pool.
create_mirror(once per token) creates the mirror and its Token-2022 mint, with the metadata-pointer extension pointing at itself and the token-metadata extension holding the HELIX token's name, symbol and uri: wallets list it, and anyone can open a pool for it on another Solana DEX; Jupiter can route it once it has a pool somewhere Jupiter indexes. Its mint authority is the mirror; it has no freeze authority. A launch can be mirrored once it graduated, so the curve stays the only market before then.bridge_out(amount)moves the HELIX tokens, through the token's hook, into the mirror's vault holding, and mints the same amount of the mirror to the sender's Token-2022 account (what the vault received, if a hook takes a cut).bridge_back(amount)burns the mirror tokens (the owner signs) and returns the HELIX tokens from the vault, through the hook.
| Account | Address | Size | Rent |
|---|---|---|---|
| Wrapper | ["wrapper", spl_mint] | 192 B | 0.0022 SOL |
| Wrapped HELIX mint | ["wrapped", spl_mint] | 448 B | 0.004 SOL |
| Vault (in) | the wrapper’s associated token account | 165 B+ | paid to the token program |
| Mirror | ["mirror", helix_mint] | 160 B | 0.002 SOL |
| Mirror mint | ["mirror-mint", helix_mint] | 234 B + metadata | about 0.004 SOL |
| Vault (out) | ["holding", helix_mint, mirror] | 184 B | 0.0022 SOL |
| Instruction | Tag |
|---|---|
register_wrapper | 50 |
wrap(amount) | 51 |
unwrap(amount) | 52 |
create_mirror | 53 |
bridge_out(amount) | 54 |
bridge_back(amount) | 55 |
A Token-2022 mint with any of these extensions is refused, because each could freeze, seize or block what the vault holds:
- permanent delegate (anyone it names can move the vault's tokens);
- transfer hook (another program could refuse the vault's transfers);
- non-transferable, default account state (frozen accounts), pausable, permissioned burn;
- confidential transfers and confidential mint/burn (the vault couldn't see its balance).
- A HELIX token's rules run on HELIX. Its burn, creator fee and holder fee apply to trades on the HELIX DEX; its SPL mirror trades freely elsewhere without them.
- The mirror's vault is left out of holder rewards, like the pool: rewards go to holders on the HELIX standard. Bring a mirror back to earn them.
- A creator lock or an early-buyer lock still holds: locked tokens can't be bridged out, because the transfer into the vault is refused.
- A wrapped token can't be mirrored (unwrap it instead), so nothing goes round in circles.
import { ix, mirrorAddress, mirrorMintAddress, holdingAddress, ataAddress, hookAccounts, TOKEN_2022_PROGRAM_ID } from '@helixfi/sdk';
const mirror = await mirrorAddress(mint);
const mirrorMint = await mirrorMintAddress(mint);
const a = {
owner, helixMint: mint, mirror, mirrorMint,
vault: await holdingAddress(mint, mirror),
ownerHolding: await holdingAddress(mint, owner.address),
ownerToken: await ataAddress(owner.address, mirrorMint, TOKEN_2022_PROGRAM_ID),
hook: await hookAccounts(mint, mintAccount), // the kit needs the launch; an external hook its accounts
};
const ixs = [
ix.createMirror({ payer: owner, helixMint: mint, mirror, mirrorMint, vault: a.vault, launch }), // first time only
ix.createAtaIdempotent({ payer: owner, ata: a.ownerToken, owner: owner.address, mint: mirrorMint, tokenProgram: TOKEN_2022_PROGRAM_ID }),
ix.bridgeOut(a, amount),
];Bridge in is the same shape with ix.registerWrapper, ix.wrap and ix.unwrap. See the SDK and the bridge page.