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

# Lend

> Open and settle a lending position on Solana in under 30 minutes.

This picks up where [Setup](/guide/quickstart/setup) left off and uses the `vanish`, `signMessage`, `broadcast`, and `commit` helpers defined there. There is no deposit step - the funds are advanced from Vanish's trading accounts.

***

## Open a Position

A position advances funds from Vanish's trading accounts into a one-time wallet and runs your own instructions against them in the same transaction.

<Steps>
  <Step title="Get a one-time wallet for the position">
    <CodeGroup>
      ```typescript TypeScript theme={null}
      const PROTOCOL_LABEL = 'kamino-lend-v2';
      const swTimestamp    = Date.now().toString();

      const { smart_wallet_id: smartWalletId, address: positionWallet } =
        await vanish('/borrow/smart-wallet', {
          method: 'POST',
          body: JSON.stringify({
            user_address:   userKeypair.publicKey.toBase58(),
            protocol_label: PROTOCOL_LABEL,
            timestamp:      swTimestamp,
            user_signature: signMessage(
              `borrow-smart-wallet:${PROTOCOL_LABEL}:${swTimestamp}`, userKeypair
            ),
          }),
        });
      ```

      ```rust Rust theme={null}
      const PROTOCOL_LABEL: &str = "kamino-lend-v2";
      let sw_timestamp = chrono::Utc::now().timestamp_millis().to_string();

      let wallet = vanish(client, api_key, "/borrow/smart-wallet", Some(&serde_json::json!({
          "user_address":   user_keypair.pubkey().to_string(),
          "protocol_label": PROTOCOL_LABEL,
          "timestamp":      &sw_timestamp,
          "user_signature": sign_message(
              &format!("borrow-smart-wallet:{PROTOCOL_LABEL}:{sw_timestamp}"), &user_keypair,
          ),
      }))).await?;

      let smart_wallet_id  = wallet["smart_wallet_id"].as_u64().unwrap();
      let position_wallet  = wallet["address"].as_str().unwrap();
      ```
    </CodeGroup>

    Store `smart_wallet_id` against the position. Unlike a trade wallet, this one is reused for every lending action on this position.
  </Step>

  <Step title="Build your instructions">
    Assemble your own deposit or open instructions into a single **unsigned** transaction, with the position's one-time wallet as signer and fee payer.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
      const BORROW    = '250000000'; // 250 USDC — USDC has 6 decimals

      const openInstructions = await buildOpenInstructions({
        authority: new PublicKey(positionWallet),
        mint:      new PublicKey(USDC_MINT),
        amount:    BORROW,
      });

      const { blockhash } = await connection.getLatestBlockhash();
      const openTx = new Transaction({
        feePayer:        new PublicKey(positionWallet),  // must be the one-time wallet
        recentBlockhash: blockhash,
      }).add(...openInstructions);

      // serialize UNSIGNED — Vanish appends its own instruction and signs the result
      const mainTx = openTx
        .serialize({ requireAllSignatures: false, verifySignatures: false })
        .toString('base64');
      ```

      ```rust Rust theme={null}
      use solana_sdk::message::Message;

      const USDC_MINT: &str = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
      const BORROW: &str    = "250000000"; // 250 USDC — USDC has 6 decimals

      let wallet_pubkey = position_wallet.parse::<Pubkey>().unwrap();
      let open_instructions = build_open_instructions(&wallet_pubkey, USDC_MINT, BORROW);

      let blockhash = rpc.get_latest_blockhash()?;
      let message = Message::new_with_blockhash(
          &open_instructions,
          Some(&wallet_pubkey),  // must be the one-time wallet
          &blockhash,
      );

      // serialize UNSIGNED — Vanish appends its own instruction and signs the result
      let main_tx = general_purpose::STANDARD
          .encode(bincode::serialize(&Transaction::new_unsigned(message))?);
      ```
    </CodeGroup>
  </Step>

  <Step title="Open the position and commit">
    <CodeGroup>
      ```typescript TypeScript theme={null}
      const BORROW_SOL = '2200000'; // ATA rent the first time this position uses the token
      const BORROW_TIP = '10000';   // only applied if a two-transaction bundle is used
      const bTimestamp = Date.now().toString();

      const position = await vanish('/borrow/initiate', {
        method: 'POST',
        body: JSON.stringify({
          smart_wallet_id:      smartWalletId,
          user_address:         userKeypair.publicKey.toBase58(),
          source_token_address: USDC_MINT,
          amount:               BORROW,
          loan_additional_sol:  BORROW_SOL,
          jito_tip_amount:      BORROW_TIP,
          main_tx:              mainTx,
          timestamp:            bTimestamp,
          user_signature: signMessage(
            `borrow:${smartWalletId}:${USDC_MINT}:${BORROW}:${BORROW_SOL}:${bTimestamp}:${BORROW_TIP}`,
            userKeypair
          ),
        }),
      });

      await broadcast(position);   // no-op when Vanish submitted a bundle instead
      const positionCommit = await commit('/borrow/commit', position.tx_id);

      console.log('Status:', positionCommit.status, 'Changes:', positionCommit.balance_changes);
      ```

      ```rust Rust theme={null}
      const BORROW_SOL: &str = "2200000"; // ATA rent the first time this position uses the token
      const BORROW_TIP: &str = "10000";   // only applied if a two-transaction bundle is used

      let b_timestamp = chrono::Utc::now().timestamp_millis().to_string();

      let position = vanish(client, api_key, "/borrow/initiate", Some(&serde_json::json!({
          "smart_wallet_id":      smart_wallet_id,
          "user_address":         user_keypair.pubkey().to_string(),
          "source_token_address": USDC_MINT,
          "amount":               BORROW,
          "loan_additional_sol":  BORROW_SOL,
          "jito_tip_amount":      BORROW_TIP,
          "main_tx":              main_tx,
          "timestamp":            &b_timestamp,
          "user_signature": sign_message(
              &format!("borrow:{smart_wallet_id}:{USDC_MINT}:{BORROW}:{BORROW_SOL}:{b_timestamp}:{BORROW_TIP}"),
              &user_keypair,
          ),
      }))).await?;

      broadcast(&rpc, &position).await?;   // no-op when Vanish submitted a bundle instead
      let position_commit = commit(
          client, api_key, "/borrow/commit", position["tx_id"].as_str().unwrap(),
      ).await?;

      println!("Status: {} Changes: {}", position_commit["status"], position_commit["balance_changes"]);
      ```
    </CodeGroup>

    The funds now sit in the position's one-time wallet, and the position is open until you settle it.
  </Step>
</Steps>

***

## Settle the Position

Settling returns the advanced funds and, with `cleanup_leftover_sol` set, closes the position. Build `main_tx` exactly as in the step above - unsigned, with the position's one-time wallet as signer - using your own withdraw or close instructions.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const SETTLE  = '253000000'; // amount landing back in the one-time wallet
  const CLEANUP = true;        // true only on the settle that closes the position

  const closeInstructions = await buildCloseInstructions({
    authority: new PublicKey(positionWallet),
    mint:      new PublicKey(USDC_MINT),
    amount:    SETTLE,
  });

  const { blockhash: sBlockhash } = await connection.getLatestBlockhash();
  const settleMainTx = new Transaction({
    feePayer:        new PublicKey(positionWallet),
    recentBlockhash: sBlockhash,
  })
    .add(...closeInstructions)
    .serialize({ requireAllSignatures: false, verifySignatures: false })
    .toString('base64');

  const sTimestamp = Date.now().toString();

  const settle = await vanish('/borrow/settle', {
    method: 'POST',
    body: JSON.stringify({
      smart_wallet_id:      smartWalletId,
      user_address:         userKeypair.publicKey.toBase58(),
      token_address:        USDC_MINT,
      amount:               SETTLE,
      loan_additional_sol:  '0',   // the wallet already holds SOL from opening the position
      cleanup_leftover_sol: CLEANUP,
      main_tx:              settleMainTx,
      timestamp:            sTimestamp,
      user_signature: signMessage(
        `settle:${smartWalletId}:${USDC_MINT}:${SETTLE}:0:${CLEANUP}:${sTimestamp}`,
        userKeypair
      ),
    }),
  });

  // settle always returns a signed transaction — you always broadcast it
  await broadcast(settle);
  const settleResult = await commit('/borrow/commit', settle.tx_id);

  console.log('Status:', settleResult.status, 'Type:', settleResult.action_type); // settle
  ```

  ```rust Rust theme={null}
  const SETTLE: &str = "253000000"; // amount landing back in the one-time wallet
  const CLEANUP: bool = true;       // true only on the settle that closes the position

  let close_instructions = build_close_instructions(&wallet_pubkey, USDC_MINT, SETTLE);
  let s_blockhash = rpc.get_latest_blockhash()?;
  let settle_main_tx = general_purpose::STANDARD.encode(bincode::serialize(
      &Transaction::new_unsigned(Message::new_with_blockhash(
          &close_instructions, Some(&wallet_pubkey), &s_blockhash,
      )),
  )?);

  let s_timestamp = chrono::Utc::now().timestamp_millis().to_string();

  let settle = vanish(client, api_key, "/borrow/settle", Some(&serde_json::json!({
      "smart_wallet_id":      smart_wallet_id,
      "user_address":         user_keypair.pubkey().to_string(),
      "token_address":        USDC_MINT,
      "amount":               SETTLE,
      "loan_additional_sol":  "0",   // the wallet already holds SOL from opening the position
      "cleanup_leftover_sol": CLEANUP,
      "main_tx":              settle_main_tx,
      "timestamp":            &s_timestamp,
      "user_signature": sign_message(
          &format!("settle:{smart_wallet_id}:{USDC_MINT}:{SETTLE}:0:{CLEANUP}:{s_timestamp}"),
          &user_keypair,
      ),
  }))).await?;

  // settle always returns a signed transaction — you always broadcast it
  broadcast(&rpc, &settle).await?;
  let settle_result = commit(
      client, api_key, "/borrow/commit", settle["tx_id"].as_str().unwrap(),
  ).await?;

  println!("Status: {} Type: {}", settle_result["status"], settle_result["action_type"]); // settle
  ```
</CodeGroup>

***

## Before Going Live

Work through the [Integration](/guide/integration/overview) pages to complete your integration, and verify:

* Every field in your `/trade/create`, `/borrow/initiate`, and `/borrow/settle` requests is correct, including `split_repay`, `loan_additional_sol`, and `cleanup_leftover_sol`
* Your signing format matches the exact message for each endpoint, and the value order is right - [`timestamp`](/guide/integration/signing) is second from last on trade and lending, last on withdraw and settle
* You're fetching a fresh one-time wallet for every trade, and reusing the position's wallet across lending actions
* Your transactions are **unsigned** before submission, timestamps are in **milliseconds**, and signatures are **base64**
* You handle every commit status, and poll with the original `tx_id` rather than creating a new transaction
* You call [`/account/pending`](/api-reference/account/get_pending_actions) and [`/borrow/pending`](/api-reference/lending/pending) on startup to catch anything uncommitted
* You understand the same-wallet-in, same-wallet-out rule for withdrawals

***

## Next Steps

* [Lending](/guide/integration/lending) - The full reference for the lending and settle flows, and reading position state.
* [Trade](/guide/quickstart/trade) - Fund a balance and execute a private trade.
* [Error Handling](/guide/handling) - Commit statuses and recovering interrupted flows.
