> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kimia.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Lock a Fixed Rate

> Use the intent-router to guarantee a minimum APY over a chosen duration.

<style>
  {`
    .katex-display {
      overflow-x: auto;
      overflow-y: hidden;
      scrollbar-width: none;
      -ms-overflow-style: none;
    }
    .katex-display::-webkit-scrollbar {
      display: none;
      height: 0;
      width: 0;
    }
    `}
</style>

This is the flagship flow: deposit USDC, split into PT+YT, sell YT on the AMM,
and have the intent-router attest that the achieved APY cleared your target.

## The three transactions

<Steps>
  <Step title="TX1, Open the session + deposit">
    1. `intent-router::create_session(target_rate, duration, amount, market, pool)`
    2. `delta-vault::deposit(amount, open_perp=true, size_amount)`
    3. `intent-router::record_step1`, reads vault share delta, asserts delivery.
  </Step>

  <Step title="TX2, Split + attest">
    1. `split-engine::deposit(vault_shares)`
    2. `intent-router::record_step2`, asserts PT + YT minted 1:1.
  </Step>

  <Step title="TX3, Swap + verify rate">
    1. `yield-amm::swap(YT → underlying)` (or equivalently `PT → underlying`
       after you hold both)
    2. `intent-router::record_step3(pt_sold, underlying_received)`
       re-derives the achieved APY and reverts if below `target_rate`.
  </Step>
</Steps>

## Client pseudocode

```ts theme={null}
const sessionId = BigInt(Date.now());

// TX1
await sendTransaction([
  getCreateSessionInstruction({
    owner: wallet,
    sessionId,
    targetRate: 250_000_000n,   // 25% APY (9-decimal FP)
    duration: 30n * 86400n,     // 30 days
    amount: 1_000_000_000n,     // 1,000 USDC
    market, pool,
  }),
  getDepositInstruction({ /* delta-vault args */ }),
  getRecordStep1Instruction({ session, sharesBefore, sharesAfter }),
]);

// TX2
await sendTransaction([
  getSplitDepositInstruction({ /* split-engine args */ }),
  getRecordStep2Instruction({ session, ptBefore, ptAfter, ytBefore, ytAfter }),
]);

// TX3
await sendTransaction([
  getSwapInstruction({ /* yield-amm args — sell YT for underlying */ }),
  getRecordStep3Instruction({
    session,
    ptSold, underlyingReceived,
  }),
]);
```

## What the router enforces on step 3

$$
\text{discount} = \text{pt\_sold} - \text{underlying\_received}
$$

$$
\text{achieved\_rate} = \frac{\text{discount} \times \text{ONE} \times \text{SECONDS\_PER\_YEAR}}{\text{underlying\_received} \times \text{duration}}
$$

The tx reverts unless $\text{achieved\_rate} \geq \text{session.target\_rate}$.

If the AMM moved against you between TX2 and TX3, `record_step3` reverts
your PT + YT stay in your wallet, and you can retry or unwind manually.

## What you're left with

* **PT** equal to your original share count, redeemable 1:1 at maturity.
* **USDC** received from selling YT, the **prepaid fixed yield**.
* An on-chain receipt (`IntentFulfilled` event) any integrator can verify.

## Read next

<CardGroup cols={2}>
  <Card title="Fixed-rate intents concept" icon="route" href="/concepts/fixed-rate-intents">
    Why this is split across three txs.
  </Card>

  <Card title="intent-router reference" icon="book" href="/programs/intent-router">
    Account + instruction layout.
  </Card>
</CardGroup>
