# Welcome to Castle 🏰

Castle is building the next generation of crypto-native products that enable organizations to deploy their assets in a risk-conscious manner. We empower protocols, companies, and DAOs with the decentralized financial tools they need to function at their highest capacity and execute on their vision. Time wasted in the trenches of DeFi is better spent innovating, scaling, and achieving goals.&#x20;

### The Problem&#x20;

Earning yield is cumbersome and time intensive, yet crucial to long-term success. Besides the unmanageable UIs that plague crypto, optimal strategies require technical and financial expertise that most projects and DAOs don’t have in-house. Current offerings prioritize maximizing APY (which is often far lower than advertised) over proper management of the numerous, opaque risks present in today’s DeFi ecosystem.&#x20;

### The Solution&#x20;

We create risk-managed, low-maintenance products that allow DAOs to secure their financial future and focus on their objectives. Castle’s ecosystem of products deliver maximal, predictable yield while minimizing risk to ensure that DAOs always have the means to fund operations and grow their treasury, regardless of market conditions. At Castle, we are simplifying treasury management, freeing up day-to-day bandwidth for web3 builders so they can focus on the development and growth of their protocols.

**Castle does NOT currently have a token.**


# Castle App

Get started with Castle using the web app.

The Castle web app ([**https://app.castle.finance/**](https://app.castle.finance/)) provides everything you need to select a vault, **deposit** or **withdraw**, and view useful analytics.

![](/files/MLKJa5Dc05eJIe6hJZdr)

View where the protocol is currently sourcing yield as well as historical information about the underlying protocols:

![Current allocations of the specific vault](/files/3NDx2SIWiPvxjydAhpBl)

![Historical APYs of all the different underlying protocols, included Castle's blended APY](/files/b0q4nLRY3DYnCi8WX05R)


# Realms Integration for DAOs

Video guide on how DAOs can use Castle's integration with Realms to access our products.

DAOs using [Realms](https://realms.today/realms) (<https://realms.today/realms>) can easily access our risk-managed Vault. Simply create a new proposal and:

1. Select either the `"Castle: Deposit into Vault"` or `"Castle: Withdraw from Vault"`
2. Select a `Source account`: the SPL token account from which to send tokens. This will be either the Deposit Asset (e.g. USDC) or the LP token
3. Select a `Castle Vault Destination:` The actual Vault you will be depositing into or withdrawing from.
4. Enter an `Amount`: the amount of SPL token to deposit or withdraw.

![https://realms.today/realms](/files/vgtwIpDQqHZKzaHK6i55)

### Realms Video Walkthrough Guide

{% embed url="<https://www.loom.com/share/3af02f31ec60403e9cfba1a5554e73a6>" %}


# Wallet View

Easily view a wallet's balance that is not connected to the web app. This is primarily useful for users who want to see a DAO's current holdings in Castle.

Here's an example url (format: `/vaults/[vaultID]/wallet/[walletID]`): <https://app.castle.finance/vaults/3tBqjyYtf9Utb1NNsx4o7AV1qtzHoxsMXgkmat3rZ3y6/wallet/AMa5ReLsamxic4jm4DPe1QN4xxPFYFx42bYCj65yb5i7>

![](/files/YjRttAfJOEMPdNxg4emg)


# Vault: Token Savings Account

Vault provides the safest yield for risk-conscious DAOs and their communities.

### What is the Vault?

The Castle Vault is a **token savings account** that safely earns yield across the Solana ecosystem, similar to a money market fund in traditional finance. It's built with three principles in mind:

1. **Principal Preservation** – Risk management measures are implemented that prioritize safety.
2. **Yield** – Vault autonomously rebalances across different lending markets to optimize returns.
3. **Instant Liquidity** – Users can seamlessly deposit and withdraw into Vault with no lockup periods.

Minimizing risk of principal loss is prioritized over maximizing returns. DAOs utilize Vault for various goals, from funding operating expenditures to growing corporate savings accounts and protocol insurance funds.&#x20;

When stablecoins are deposited into Vault, they are forwarded to a diversified set of yield-earning sources. Every minute, the contract rebalances between sources to optimize the yield earned. Vault is built on top of the most reputable lending primitives in the Solana ecosystem.&#x20;

We source yield from the following protocols:&#x20;

* Solend&#x20;
* Port Finance&#x20;
* Jet Protocol&#x20;

Additional integrations with Mango, Saber, Mercurial, and others, are under development.

### Risk Management

In order to minimize the likelihood of principal loss, Vault implements the following risk management measures:

* **Overexposure Control:** Vault limits exposure to any single underlying protocol.
* **Underlying Liquidity:** Vault ensures that there is liquidity at all times by never lending funds to money markets near a 100% utilization rate.
* **Protocol Security:** Underlying protocols are open-source, audited, have verifiable builds, and have decentralized deployment keys.
* **Audit:** Bramah Systems, an expert in distributed ledger security, has conducted a full audit of our protocol’s codebase and found no unresolved issues. As we develop additional features, future builds will be reviewed in the same manner.
* **Emergency Brake:** Castle’s team will be able to “emergency brake”, which immediately withdraws all funds from underlying protocols into Vault’s reserves. This will only be used in extraordinary circumstances such as Solana network congestion.

### Roadmap

* **Additional Yield Sources:** Continue integrating with DeFi protocols to increase capacity and further diversify risks.
* **Insurance:** Protection against stablecoin de-pegging and smart contract exploits of underlying protocols.
* **Unusual Behavior Detection:** Monitor the price of stablecoins and rebalance out if unusual behavior is detected.
* **Yield Enhancement:** Execute arbitrage opportunities between the lending and borrowing rates of two stable pairs.
* **Cross-chain:** Expand reach to other blockchains, allowing for a wider universe of deposit assets and yield opportunities.


# SDK

Integrate the Castle ecosystem of products into your app to supercharge your UX

## Client-Side Integration

Client-side integrations are powered by our [SDK](https://github.com/castle-finance/castle-vault/tree/dev/sdk), which lives alongside the program code in the Vault repository. The primary actions a user takes are `deposit` and `withdraw`.&#x20;

The SDK exposes `deposit()` and `withdraw()`, both abstract away intermediate instructions like creating ATAs, (un)wrapping sol, refreshing or reconciling the vault.&#x20;

If you run into transaction size limits (for example: sending transactions as part of governance proposals that increase the bytes to over 1232), then you can split up certain instructions into their own transactions. Each section will provide code for both **single SDK call** and **multi-SDK call** cases.

Here's the full list of instructions the vault contract expects:

1. `refresh`: (permissionless) Refreshes the vaults accounts
2. `reconcile`: (permissionless) Withdraws from the underlying lending markets to allow a user to withdraw
3. `deposit`: Sends reserve token (e.g. USDC) assets into the vault in exchange for LP tokens
4. `withdraw`: Sends LP tokens into the vault in exchange for reserve token assets

### Vault Client

#### Installation

SDK NPM: <https://www.npmjs.com/package/@castlefinance/vault-sdk>

`yarn add @castlefinance/vault-sdk`

#### Usage

The `VaultClient` contains static and member functions for loading information about a specific vault, along with all the necessary instructions for depositing and withdrawing.

```typescript
import { VaultClient, VaultConfig } from '@castlefinance/vault-sdk'

// Pull down the appropriate vault from the API.
const configResponse = await fetch('https://api.castle.finance/configs')
const vaults = (await response.json()) as VaultConfig[]
const vault = vaults.find(
  (v) => v.deploymentEnv == 'mainnet' && v.token_label == 'USDC'
)


// Create the vault client
const vaultClient = await VaultClient.load(
  new anchor.Provider(...),
  vault.vault_id,
  vault.deploymentEnv
)
```

Here is an example deployed vault along with the Anchor annotations: <https://explorer.solana.com/address/9n6ekjHHgkPB9fVuWHzH6iNuxBxN22hEBryZXYFg6cNk/anchor-account?cluster=devnet>

### Deposit

Here are the following instructions needed to make a deposit:

1. Create the user's LP token account if it does not exist
2. Refresh the Vault
3. Deposit into the Vault

*Note*: The refresh and deposit instructions need to be sent in the same transaction.

#### Deposit (single SDK call)

```typescript
// Get the user's reserve token ATA
const userReserveTokenAccount = await splToken.Token.getAssociatedTokenAddress(
  ASSOCIATED_TOKEN_PROGRAM_ID,
  TOKEN_PROGRAM_ID,
  vaultClient.getReserveTokenMint(),
  reserveTokenAccountOwner, // e.g. wallet.pubkey or DAO's account
  true
);

// Deposit into the vault
const sig = await vaultClient.deposit(wallet, amount, userReserveTokenAccount)
```

#### Deposit (multi-SDK call)

Create LP Token Account Transaction:

```typescript
let createLpAcctIx: TransactionInstruction | undefined = undefined

// Owner of the SPL Token account, e.g. the user or DAO. 
// In this example we assume a wallet logged-in user.
const reserveTokenAccountOwner = wallet.publicKey

const userLpTokenAccount = await Token.getAssociatedTokenAddress(
  ASSOCIATED_TOKEN_PROGRAM_ID,
  TOKEN_PROGRAM_ID,
  vaultClient.getLpTokenMint(),
  reserveTokenAccountOwner,
  true
)

const userLpTokenAccountInfo =
  await vaultClient.program.provider.connection.getAccountInfo(
    userLpTokenAccount
  )

if (userLpTokenAccountInfo == null) {
  createLpAcctIx = Token.createAssociatedTokenAccountInstruction(
    ASSOCIATED_TOKEN_PROGRAM_ID,
    TOKEN_PROGRAM_ID,
    vaultClient.getLpTokenMint(),
    userLpTokenAccount,
    reserveTokenAccountOwner,
    wallet.publicKey // payer
  )
}

// Construct, sign, and send
const tx = new Transaction.add(createLpAcctIx)
const signedTx = await wallet.signTransaction(tx)
const sig = connection.send(signedTx)
```

Refresh and Deposit into the Vault:

```typescript
// Get the refresh instruction
const refreshIx = vaultClient.getRefreshIx()

// Get the user reserve ATA
const userReserveTokenAccount = await Token.getAssociatedTokenAddress(
  ASSOCIATED_TOKEN_PROGRAM_ID,
  TOKEN_PROGRAM_ID,
  vaultClient.getReserveTokenMint(),
  reserveTokenAccountOwner,
  true,
)

// Get the deposit instruction
const depositIx = vaultClient.getDepositIx(
  new anchor.BN(amount),
  reserveTokenOwner,
  userLpTokenAccount,
  userReserveTokenAccount,
)

// Construct, sign, and send
let tx = new Transaction();
tx.instructions = [refreshIx, depositIx];
const signedTx = await wallet.signTransaction(tx)
const sig = connection.send(signedTx)
```

### Withdraw

Withdrawing requires the following transactions to be sent:

1. Transaction #1
   1. Refresh the vault
   2. Reconcile the markets
2. Transaction #2
   1. Refresh the vault
   2. Withdraw from the vault

#### Withdraw (single SDK call)

```typescript
const sig = await vaultClient.withdraw(wallet, amount)
```

#### Withdraw (multi-SDK call)

Create the reconcile transactions:

```typescript
// Get reconcile transactions (note: each tx has a prepended refresh ix)
const txs = await vaultClient.getReconcileTxs(amount)

// Send all of them
txs.forEach(tx => {
  ...
})
```

Note: There may be up to 3 different reconcile transactions. Simply send off all of them.

Create the ATAs as needed and withdraw from the vault:

```typescript
// Create the user reserve ATA if it does not exist already
let createReserveAcctIx: TransactionInstruction | undefined = undefined
const userReserveTokenAccount = await Token.getAssociatedTokenAddress(
  ASSOCIATED_TOKEN_PROGRAM_ID,
  TOKEN_PROGRAM_ID,
  vaultClient.getReserveTokenMint(),
  lpTokenAccountOwner,
  true
)
const userReserveTokenAccountInfo =
  await vaultClient.program.provider.connection.getAccountInfo(
    userReserveTokenAccount
  )
if (userReserveTokenAccountInfo == null) {
  createReserveAcctIx = Token.createAssociatedTokenAccountInstruction(
    ASSOCIATED_TOKEN_PROGRAM_ID,
    TOKEN_PROGRAM_ID,
    vaultClient.getReserveTokenMint(),
    userReserveTokenAccount,
    lpTokenAccountOwner,
    wallet.publicKey
  )
}

// Get the refresh instruction
const refreshIx = vaultClient.getRefreshIx()

// Get the LP ATA
const userLpTokenAccount = await Token.getAssociatedTokenAddress(
  ASSOCIATED_TOKEN_PROGRAM_ID,
  TOKEN_PROGRAM_ID,
  vaultClient.getLpTokenMint(),
  lpTokenAccountOwner,
  true
)

// Get withdraw instruction. User selects the LP token to deposit back
// into the vault in exchange for the reserve token
const withdrawIx = vaultClient.program.instruction.withdraw(
  new anchor.BN(amount),
  lpTokenAccountOwner,
  userLpTokenAccount,
  userReserveTokenAccount,
)

// Construct, sign, and send
let tx = new Transaction();
tx.instructions = [refreshIx, withdraw];
const signedTx = await wallet.signTransaction(tx)
const sig = connection.send(signedTx)
```

## Final Notes

These docs are still a work-in-progress. Please reach out to our Twitter or Discord if you have any questions or something is not working.


# Program

Program Code Repository: <https://github.com/castle-finance/castle-vault>

Functions in the program are created by bundling one or more instructions into a transaction. This document will first explain what each instruction does on its own and then how they are bundled together into various user-facing functions in the SDK.

### Instructions

#### Initialize

Creates a new vault

#### Deposit

Exchanges reserve tokens for vault LP tokens

#### Withdraw

Exchanges vault LP tokens for reserve tokens

#### Rebalance

Calculates and stores the desired allocations to integrated lending markets based on the vault strategy type

Also emits and anchor event containing the new allocations

Required before any reconcile IX is called

#### Refresh \[Jet | Port | Solend]

Refreshes the reserves of the given lending reserve, which is required before any deposit or withdrawal

Calculates the value of the vault held in the given lending reserve, denominated in the reserve token

#### Consolidate Refresh

Calculates the total value of the vault, denominated in the reserve token. This is required before any deposit or withdrawal from the vault

#### Reconcile \[Jet | Port | Solend]

Deposits and withdraws from the given lending market according to the allocations stored by the rebalance IX

### Functions

#### Initialize

IXs

* Initialize

#### Deposit

IXs

* (if reserve token is SOL) Wrap SOL into SPL token
* (if doesn't exist already) Create account for LP token
* Refresh
* Deposit
* (if reserve token is SOL) Close intermediate account created during wrapping

#### Withdraw

IXs

* Refresh
* (if withdraw amount is less than in vault reserves) Reconcile&#x20;
* (if doesn't exist already) Create account for reserve token
* Withdraw
* (if reserve token is SOL) Unwrap from SPL token to SOL

#### Rebalance

IXs

* Refresh
* Rebalance
* Reconcile IXs


# URLs and Addresses

### Mainnet

[`Cast1eoVj8hwfKKRPji4cqX7WFgcnYz3um7TTgnaJKFn`](https://explorer.solana.com/address/Cast1eoVj8hwfKKRPji4cqX7WFgcnYz3um7TTgnaJKFn)

{% embed url="<https://app.castle.finance>" %}
Mainnet App
{% endembed %}

USDC Vault: 3tBqjyYtf9Utb1NNsx4o7AV1qtzHoxsMXgkmat3rZ3y6

### Devnet Parity

[`Cast1eoVj8hwfKKRPji4cqX7WFgcnYz3um7TTgnaJKFn`](https://explorer.solana.com/address/Cast1eoVj8hwfKKRPji4cqX7WFgcnYz3um7TTgnaJKFn?cluster=devnet)

{% embed url="<https://devnet.castle.finance>" %}
Devnet Parity App
{% endembed %}

SOL Vault: DT6AaP15L4ee56nGY55JAfBdhgWVdZqh7US2EqZwnQvH

### Devnet Staging

[`4tSMVfVbnwZcDwZB1M1j27dx9hdjL72VR9GM8AykpAvK`](https://explorer.solana.com/address/4tSMVfVbnwZcDwZB1M1j27dx9hdjL72VR9GM8AykpAvK?cluster=devnet)

{% embed url="<https://devnet-staging.castle.finance>" %}
Devnet Staging App
{% endembed %}

SOL Vault: 7MXreZLSP1Xm9EiLvEf2gZKsQqeuyUHuL54vVSyvFfZi


# Security Policy

## Bug Bounty

Castle Labs is now offering a Bug Bounty program for security researchers that discover vulnerabilities or exploits in Castle's Solana programs.

Security vulnerabilities or other high-severity vulnerabilities that are successfully reported following the terms of the Bug Bounty program can be eligible for a reward of up to **$100,000**, depending on severity.

### Rewards

| Severity   | Description                                                                                                     | Bounty                                                       |
| ---------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Critical   | Bugs that freeze user funds or drain the contract's holdings or involve theft of funds without user signatures. | 10% of the value of the hack up to $100,000.                 |
| High       | Bugs that could *temporarily* freeze user funds or incorrectly assign value to user funds.                      | $10,000 to $25,000 per bug, assessed on a case by case basis |
| Medium/Low | Bugs that don't threaten user funds                                                                             | $1,000 to $5,000 per bug, assessed on a case by case basis   |

The severity guidelines are based on [Immunefi's classification system.](https://immunefi.com/severity-updated/)﻿

Note that these are simply guidelines for the severity of the bugs. Each bug bounty submission will be evaluated on a case by case basis.

### Submission

Please message [@charlie\_you on Telegram ](https://t.me/charlie_you)or send an email to <charlie@castle.finance> with a detailed description of the attack vector. For critical and high bugs, we require a proof of concept done on a privately deployed contract. We will reach back out in 1 business day with additional questions or next steps on the bug bounty.

### Scope

The Castle Vault Solana program: <https://github.com/castle-finance/castle-vault/tree/dev/programs/castle-vault>

### Terms

* The vulnerability:
  1. Must be first reported to Castle Labs exclusively.
  2. Must not be publicly shared before reporting to Castle Labs.
  3. Must not be publicly shared during Castle Labs’ investigation and fix.
  4. Must be reproducible by Castle Labs.
  5. Should only be publicly disclosed if agreed upon after bug resolution.
* You must be the first person to report this vulnerability.
* You must not maliciously exploit the vulnerability in any way after discovery.
* You must not be subject to United States sanctions or live in any U.S.-embargoed country.


