StockwovenDocs
    AppLaunch app

    How the vault works.

    One stock, one token. The vault holds liquidity in a Meteora DAMM v2 pool that pairs two issuers' tokens of the same stock (MVP: INTCx from xStocks and INTC from Backpack). Holders own swINTC, a pro-rata claim on that liquidity. Conversions between issuers pay fees, and DAMM v2's compounding mode puts most of each fee back into the pool, so every swINTC is backed by more stock over time.

    How it fits together

    traders / Jupiter ──swap──▶ DAMM v2 pool (INTCx ↔ INTC, collect_fee_mode = Compounding)
                                  │  fee split per swap:
                                  │   20%  Meteora protocol fee
                                  │   LP fee × compounding_fee_bps  → stays in reserves (holders' yield)
                                  │   LP fee × the rest             → claimable by positions, in token B
                                  ▼
                        position NFT owned by the vault PDA
                                  │
              deposit / redeem ───┤ shares ↔ pro-rata liquidity
                                  ▼
                         swINTC (SPL mint, authority = vault PDA)
    

    The vault program is not in the swap path. Swaps go straight to cp-amm, so any router can fill them.

    Share accounting

    A share is a pro-rata claim on the vault's position liquidity, L_vault:

    • deposit s shares → add s × ceil(L_vault / supply) liquidity
    • redeem s shares → remove s × floor(L_vault / supply) liquidity
    • single-token deposit adding ΔL → mint ΔL × (1 − zap fee) / ceil(L_vault / supply) shares

    liquidity_per_share is only the launch ratio. It applies when the supply is zero.

    Two things make a share worth more stock over time:

    1. Pool fees. Compounding fees grow pool.token_b_amount while pool.liquidity stays the same, so every unit of liquidity is backed by more tokens.
    2. Vault fees. The single-token deposit keeps 0.05% of the liquidity it adds in the position without minting shares for it, so L_vault / supply rises for existing holders.

    This has three consequences:

    • No oracle, no NAV math on-chain. cp-amm's own L × reserve / L_total rule prices deposits and withdrawals. Every rounding favours the vault.
    • No donation or inflation attack. Only the vault can add liquidity to its position. Tokens sent to the vault do not change what a share is worth.
    • Dust. Redeeming a few raw share units can pay out zero of a token. cp-amm rejects that, so the transaction fails and the holder keeps the shares.

    Instructions

    InstructionWhoWhat
    initialize_vaultadminCreates the pool via initialize_customizable_pool (compounding, full range, flat fee). The vault PDA is the pool creator, so it owns the first position NFT.
    deposit(shares, max_a, max_b)anyonePulls up to max_a/max_b into vault-owned reserves, adds liquidity signed by the vault, refunds what cp-amm did not take, and mints shares.
    deposit_single(input_is_a, amount_in, min_shares)anyoneTakes one issuer's token, swaps the right part of it on the pool at the pool's price, adds both as liquidity, refunds the dust, and mints shares net of the 0.05% vault fee. min_shares bounds slippage.
    redeem(shares, min_a, min_b)holderBurns shares, then removes liquidity straight to the holder in both tokens. Never paused by the vault.
    harvestanyoneClaims the position fee to the treasury. In compounding pools that fee is in token B only. It is the protocol's cut.
    set_deposits_pausedadminCircuit breaker for issuer events (pause, freeze, depeg). Redemptions stay open.

    Reserve token accounts exist because cp-amm pulls liquidity from token accounts owned by the position's signer, which is the vault PDA.