# Deploy Feed

"Deploying" a Switchboard feed means making it available for use on-chain. With Switchboard's **managed update system**, this is simpler than ever:

* **Solana/SVM**: Feeds use **canonical OracleQuote accounts** derived deterministically from feed IDs. No explicit account creation needed—accounts are created automatically on first use.
* **EVM**: Feeds are identified by a deterministic `bytes32` ID. You submit oracle-signed updates to the Switchboard contract and read the latest update from storage.

Both chains follow the same pattern: **store your feed definition, get a feed ID, then use managed updates**.

***

### Prerequisites (all chains)

Before “deployment”, you should have:

* a feed definition (jobs + tasks) you have **simulated successfully**
* a clear understanding of:
  * what value your feed returns
  * decimal conventions (e.g., 1e8 vs 1e18)
  * which sources/jobs you trust and why

If you haven't designed and simulated your jobs yet, start here:

* [Build with TypeScript](/custom-feeds/build-and-deploy-feed/build-with-typescript.md) (code-first)
* [Build with UI](/custom-feeds/build-and-deploy-feed/build-with-ui.md) (UI-first)

***

## Solana / SVM: Deploy with Managed Updates

### What you are doing

On Solana, deployment means:

1. Choose a **queue** (oracle subnet).
2. **Store/pin** your job definition with Crossbar to get a feed hash.
3. Use the feed hash to derive the **canonical OracleQuote account** address.
4. Fetch managed update instructions and include them in your transactions.

The canonical account is created automatically on first use—no explicit initialization transaction required.

### Requirements

* A funded Solana keypair file (payer)
* A Solana RPC URL
* Your OracleJob\[] definition

Create a keypair file if you don't have one:

```bash
solana-keygen new --outfile path/to/solana-keypair.json
```

### Install

```bash
bun add @switchboard-xyz/on-demand @switchboard-xyz/common
```

### Deployment flow (TypeScript)

Below is the deployment flow using managed updates. You can merge this into the same project where you built/simulated your jobs.

```ts
import { CrossbarClient, OracleJob } from "@switchboard-xyz/common";
import {
  AnchorUtils,
  OracleQuote,
  getDefaultQueue,
  getDefaultDevnetQueue,
  asV0Tx,
} from "@switchboard-xyz/on-demand";

// 1) Your simulated job definitions
const jobs: OracleJob[] = [
  /* ... */
];

// 2) Choose cluster + RPC
const connection = /* new Connection(RPC_URL) */;

// 3) Choose the queue (oracle subnet)
const queue = await getDefaultQueue(connection.rpcUrl);
// or: const queue = await getDefaultDevnetQueue(connection.rpcUrl);

// 4) Store jobs with Crossbar and get a feedHash
const crossbarClient = CrossbarClient.default();
const { feedHash } = await crossbarClient.store(queue.pubkey.toBase58(), jobs);
console.log("Feed hash:", feedHash);

// 5) Derive the canonical OracleQuote account address
// This is deterministic - same feed hash always produces the same address
const [quoteAccount] = OracleQuote.getCanonicalPubkey(queue.pubkey, [feedHash]);
console.log("Quote account:", quoteAccount.toBase58());

// 6) Load payer (funded)
const payer = await AnchorUtils.initKeypairFromFile("path/to/solana-keypair.json");

// 7) Fetch managed update instructions
// This returns Ed25519 verification + quote storage instructions
const updateIxs = await queue.fetchManagedUpdateIxs(crossbarClient, [feedHash], {
  payer: payer.publicKey,
});

// 8) Build and send a transaction to verify everything works
const tx = await asV0Tx({
  connection,
  ixs: updateIxs,
  payer: payer.publicKey,
  signers: [payer],
});

const sig = await connection.sendTransaction(tx);
console.log("Transaction signature:", sig);
console.log("Feed deployed! Quote account:", quoteAccount.toBase58());
```

#### Using validation parameters

Validation parameters (min responses, max variance, staleness) are now specified when fetching updates or reading data, rather than at deployment time:

```ts
// When reading in your program, use QuoteVerifier with max_age
const quote_data = QuoteVerifier::new()
    .max_age(30)  // Reject data older than 30 slots
    .verify_account(quote)?;
```

#### Make it discoverable

Storing with Crossbar pins the feed definition to IPFS and makes it easier to view/debug in the Switchboard explorer. The feed hash is the key identifier you'll use throughout your integration.

***

## EVM: “Deploying” is publishing a feed ID + updating via the Switchboard contract

### Why there isn’t a dedicated “deploy feed” step on EVM

On EVM, a feed is identified by a **deterministic `bytes32` feed ID**. You can treat deployment as:

1. Obtain the feed ID (often from the Feed Builder / Explorer).
2. Store that feed ID in your consumer contract or app.
3. Fetch oracle-signed updates off-chain.
4. Submit updates on-chain via `updateFeeds`.

This is the same pattern Solana now uses with managed updates—no explicit account creation needed.

### On-chain: reading and updating

A typical Solidity integration looks like:

* Store the Switchboard contract address + your feedId
* When you need fresh data:
  * compute the required fee
  * submit `updateFeeds(updates)`
  * read `latestUpdate(feedId)`

```solidity
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {ISwitchboard} from "@switchboard-xyz/on-demand-solidity/ISwitchboard.sol";
import {Structs} from "@switchboard-xyz/on-demand-solidity/structs/Structs.sol";

contract Example {
    ISwitchboard switchboard;
    bytes32 feedId;

    error InsufficientFee(uint256 expected, uint256 received);
    error InvalidResult(int128 result);

    constructor(address _switchboard, bytes32 _feedId) {
        switchboard = ISwitchboard(_switchboard);
        feedId = _feedId;
    }

    function getFeedData(bytes[] calldata updates) external payable returns (int128) {
        uint256 fee = switchboard.getFee(updates);
        if (msg.value < fee) revert InsufficientFee(fee, msg.value);

        switchboard.updateFeeds{value: fee}(updates);

        Structs.Update memory latest = switchboard.latestUpdate(feedId);
        if (latest.result < 0) revert InvalidResult(latest.result);

        return latest.result;
    }
}
```

> Many feeds use `int128` scaled by `1e18` to avoid floating point issues.\
> Always consult the feed’s intended decimal convention.

### Off-chain: fetch encoded updates with Crossbar (TypeScript)

Use Crossbar to fetch oracle-signed updates (encoded) for submission:

```ts
import { CrossbarClient } from "@switchboard-xyz/common";

const feedId = "0x...your_feed_id...";
const crossbarNetwork = "testnet"; // or "mainnet"

const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");

// Recommended preflight for Feed Builder feeds:
await crossbar.fetchOracleFeed(feedId);
await crossbar.simulateFeed(feedId, false, undefined, crossbarNetwork);

const response = await crossbar.fetchV2Update([feedId], {
  chain: "evm",
  network: crossbarNetwork,
  use_timestamp: true,
});

if (!response.encoded) {
  throw new Error("Crossbar returned no encoded update payload");
}

const updates = [response.encoded];

// submit `updates` to your contract method that calls updateFeeds(...)
```

Recommended EVM preflight order for custom feeds:

1. `GET /v2/fetch/{feedId}` or `crossbar.fetchOracleFeed(feedId)` to confirm the definition exists
2. `GET /v2/simulate/{feedId}?network=testnet|mainnet` or `crossbar.simulateFeed(...)` to confirm the jobs resolve
3. `GET /v2/update/{feedId}?chain=evm&network=testnet|mainnet&use_timestamp=true` or `crossbar.fetchV2Update(...)` to obtain the EVM payload

Use the same deterministic `feedId` / feed hash from Feed Builder or Explorer for all three steps.

> Do not pass a Feed Builder `bytes32` feed ID into `fetchEVMResults()` or `simulateEVMFeeds()` unless you are intentionally using the legacy aggregator-based EVM flow.

***

### Do we need “deployment docs” for other chains?

Switchboard supports additional chains with chain-specific SDKs and verification flows (e.g., Move-based environments). Many of these integrations follow the **EVM-style** model: you fetch oracle consensus off-chain and include a verification/update step inside your transaction, rather than creating a dedicated on-chain “feed account”.

If you’re targeting a non-Solana chain, treat “deployment” as:

1. Create/publish a feed definition and get its feed ID/address.
2. Use the chain’s SDK to fetch and verify oracle results in your transaction flow.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.switchboard.xyz/custom-feeds/build-and-deploy-feed/deploy-feed.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
