> For the complete documentation index, see [llms.txt](https://docs.triton.one/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.triton.one/solana/sending-transactions/shield-mev-protection.md).

# Shield Protection

Yellowstone Shield MEV protection: on-chain validator allowlist or blocklist, attached with forwardingPolicies or the Solana-ForwardingPolicies header.

Yellowstone Shield lets you control which validators handle your Solana transactions. You create an on-chain policy listing validators you trust (an allowlist) or do not trust (a blocklist), attach the policy when you send, and your transaction only goes to validators that match.

Solana's leader schedule is deterministic, so you often know which validator will process your transaction. If that leader runs sandwich attacks (inserting transactions before and after yours to extract value), frontrunning (copying and executing your transaction idea before you), or other harmful MEV, a normal send still routes to them. Shield is how you opt out. Background: [Introducing Yellowstone Shield](https://blog.triton.one/introducing-yellowstone-shield).

## Use cases

* **Trading apps and wallets** protecting swaps from sandwich attacks and frontrunning by never sending to validators known for them.
* **Senders that route only to vetted validators**: top validators by stake, geographically distributed sets, or performance-based allowlists.
* **RPC providers and transaction forwarders** enforcing policy-based routing for their users.

## Features and benefits

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-filter">:filter:</i> <strong>Allowlist or blocklist</strong></td><td>Two strategies: forward only to validators on your allowlist, or never to validators on your blocklist.</td><td></td></tr><tr><td><i class="fa-bolt">:bolt:</i> <strong>Out of the box on Triton</strong></td><td>Attach your policy to any send through Triton: <code>forwardingPolicies</code> on <code>sendTransaction</code>, or the <code>Solana-ForwardingPolicies</code> header on <code>/sendtx</code>. No extra infrastructure.</td><td></td></tr><tr><td><i class="fa-cube">:cube:</i> <strong>On-chain and transparent</strong></td><td>Each policy is a Program Derived Address anyone can inspect, and anyone who knows the address can use it.</td><td></td></tr><tr><td><i class="fa-key">:key:</i> <strong>Token-gated management</strong></td><td>A Token Extensions asset controls each policy. Hold a token to manage it; mint more to share control with the team.</td><td></td></tr><tr><td><i class="fa-users">:users:</i> <strong>Community policies</strong></td><td>Reuse maintained allow and deny lists from the policy explorer instead of curating your own.</td><td></td></tr><tr><td><i class="fa-database">:database:</i> <strong>Cached enforcement</strong></td><td>Policies are cached and checked in the sender via the shield store, with atomic updates and thread-safe checks.</td><td></td></tr></tbody></table>

## How it works

1. **Create a policy**: an on-chain list of identities (typically validators) with an `allow` or `deny` strategy. The policy lives at a Program Derived Address, paired with an SPL token (Token Extensions): creating it mints you 1 token and keeps you the mint authority.
2. **Attach the policy address to your transactions**, either as the `forwardingPolicies` parameter on `sendTransaction` (JSON-RPC), or as the `Solana-ForwardingPolicies` HTTP header when you send through `/sendtx`. The header is only read on `/sendtx`: on a JSON-RPC `sendTransaction` call it is ignored, and the transaction goes out without Shield protection.
3. **The sender checks your policy on each send that carries it**, against every leader it would forward to (the current leader and the next one or two), and skips any leader that fails. If none pass, the transaction isn't forwarded, held or queued, although you still get its signature back.

```mermaid
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#F2EDF6','primaryBorderColor':'#7A4BA0','primaryTextColor':'#171717','lineColor':'#956FB3','secondaryColor':'#E4DBEC','tertiaryColor':'#D7C9E3','edgeLabelBackground':'#F2EDF6'},'flowchart':{'nodeSpacing':20,'rankSpacing':35,'curve':'linear'}}}%%
flowchart LR
    you["Your app"] -->|"tx + policy address"| rpc["Triton RPC / Jet"]
    rpc --> check["Policy check<br/>against upcoming leaders"]
    check -->|"leader allowed"| val["Validator"]
    check -->|"leader blocked"| drop["Skipped<br/>(not queued)"]
    style you fill:#D6EAF8,stroke:#259DD0
```

Ownership follows the token. Anyone holding a policy's token can manage it (add or remove validators), and because the token is fungible and mintable, you can mint and send tokens to share policy management with others.

The policy itself is public: anyone who knows its address can use it in their transactions.

{% hint style="info" %}
Shield only works with Shield-enabled senders (Triton RPC, or the Jet TPU client). A standard Solana RPC ignores the policy parameter and forwards the transaction as usual.
{% endhint %}

## Finding and using an existing policy

Browse the policy explorer at [validators.app/yellowstone-shield](https://www.validators.app/yellowstone-shield?network=mainnet) to see all existing policies, which validators each includes or excludes, and when it was last updated, then copy the policy address for your transactions. Common policy types:

* **Allow lists**: top validators by stake, geographically distributed validators, performance-based selection.
* **Block lists (deny lists)**: validators known for sandwich attacks or frontrunning, poor performers, community-flagged validators.

Attach the policy to your sends through Triton:

{% tabs %}
{% tab title="JSON-RPC" %}

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sendTransaction",
  "params": [
    "<base64_encoded_transaction>",
    {
      "encoding": "base64",
      "skipPreflight": true,
      "forwardingPolicies": ["<your_policy_pda>"]
    }
  ]
}
```

{% endtab %}

{% tab title="HTTP header" %}
For `/sendtx` only (JSON-RPC `sendTransaction` ignores this header). Separate multiple policies with commas:

```
Solana-ForwardingPolicies: <your_policy_pda>,<your_policy_pda2>
```

{% endtab %}

{% tab title="TypeScript" %}
The standard web3.js `sendTransaction` wrapper does not pass the policy parameter, so make the RPC call directly:

```typescript
import { Transaction } from "@solana/web3.js";
import bs58 from "bs58";

const transaction = new Transaction().add(/* your instructions */);
const signedTx = await wallet.signTransaction(transaction);
const serializedTx = bs58.encode(signedTx.serialize());

const response = await fetch("https://<your-endpoint>.mainnet.rpcpool.com/<your-token>", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "sendTransaction",
    params: [
      serializedTx,
      {
        encoding: "base58",
        skipPreflight: true,
        forwardingPolicies: ["<your_policy_pda>"],
      },
    ],
  }),
});

const result = await response.json();
const signature = result.result;
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Running your own RPC and want to support Shield?

* **Yellowstone Jet**: Shield support is built in.
* **Custom integration**: use the [yellowstone-shield-store](https://crates.io/crates/yellowstone-shield-store) crate to cache policies locally with atomic updates, check validators against policies thread-safely, and integrate the checks with your transaction forwarding logic.
  {% endhint %}

## Creating your own policy

You need the Solana CLI installed and configured, SOL for transaction fees, and a list of validator addresses.

{% stepper %}
{% step %}

### Install the Shield CLI

Build the CLI from the [yellowstone-shield repository](https://github.com/rpcpool/yellowstone-shield):

```bash
git clone https://github.com/rpcpool/yellowstone-shield
cd yellowstone-shield
cargo build --release --bin yellowstone-shield-cli
```

The build writes the binary to `./target/release/yellowstone-shield-cli`. Add that folder to your `PATH`, or run the binary by that path in the commands below.
{% endstep %}

{% step %}

### Prepare metadata

Create a JSON file describing your policy, upload it to IPFS or Arweave, and save the URL:

```json
{
  "name": "My Validator Policy",
  "symbol": "MVP",
  "description": "Blocks validators known for sandwich attacks",
  "image": "https://your-image-url.com/image.png",
  "external_url": "https://your-website.com",
  "attributes": []
}
```

{% endstep %}

{% step %}

### Create the policy

`--strategy deny` blocks the listed validators; `--strategy allow` permits only the listed validators.

```bash
yellowstone-shield-cli policy create \
  --strategy deny \
  --name "My Validator Policy" \
  --symbol "MVP" \
  --uri "https://your-metadata-url.json"
```

The CLI prints two addresses, Policy (the policy PDA) and Mint: save both. Use the Mint with `--mint` in the CLI commands below, and pass the Policy PDA in `forwardingPolicies` when you send. If you pass the mint instead, Shield can't find the policy and the transaction is never forwarded to a leader, even though you get a signature back. You receive 1 token and retain mint authority, so you can mint more tokens later to share policy management.
{% endstep %}

{% step %}

### Add validators

Create a text file with one validator address per line, then:

```bash
yellowstone-shield-cli identities add \
  --mint <your_mint_address> \
  --identities-path validators.txt
```

{% endstep %}
{% endstepper %}

**Managing the policy.** You must hold at least 1 policy token to manage it; if you transfer all your tokens away, you lose the ability to manage the policy.

```bash
# Replace the entire validator list
yellowstone-shield-cli identities update \
  --mint <mint_address> \
  --identities-path new_validators.txt

# Remove specific validators
yellowstone-shield-cli identities remove \
  --mint <mint_address> \
  --identities-path validators_to_remove.txt

# View policy details
yellowstone-shield-cli policy show --mint <mint_address>
```

## Limitations

Shield is a filter, not a guarantee of protection from sandwich attacks or transaction failures.

* **Policies need active maintenance.** New validators can join at any time and a bad actor can appear at any time. A blocklist only protects against what is on it, so the quality of protection depends entirely on how current the list is kept.
* **Strict policies can drop time-sensitive transactions.** When no eligible leader is available the transaction is dropped, not queued. Be careful pairing a tight allowlist with arbitrage or liquidations.
* **Check your policy addresses.** Triton skips an entry that isn't a valid public key, so the send goes out without that policy.
* **A valid address that isn't a policy fails the check.** This includes the policy's mint and a mistyped address that still decodes to a valid key. Triton skips each leader whose check reaches that address, so the transaction may not be forwarded.
* **Only Shield-enabled senders enforce policies.** A standard Solana RPC ignores `forwardingPolicies`, and the standard web3.js `sendTransaction` wrapper does not pass it: make direct RPC calls as shown in the TypeScript tab above.

## What's next

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-shield">:shield:</i> <strong>Protect transactions from MEV with Shield</strong></td><td>The full walkthrough: choose RPC or TPU-client enforcement, pick a policy, and protect your sends.</td><td><a href="/solana/quickstart/sending-transactions/protect-transactions-with-shield.md">Protect transactions from MEV with Shield</a></td></tr><tr><td><i class="fa-play">:play:</i> <strong>Sending transactions quickstart</strong></td><td>Send a transaction via Triton endpoints in a few minutes.</td><td><a href="/solana/sending-transactions/quickstart.md">Sending transactions quickstart</a></td></tr></tbody></table>

***

<i class="fa-life-ring">:life-ring:</i> Contact support by clicking the chat icon in your [customer dashboard](https://customers.triton.one)\ <i class="fa-briefcase">:briefcase:</i> Sales questions? [Contact us](https://triton.one/contact)\ <i class="fa-sparkles">:sparkles:</i> AI agent? Read [llms.txt](https://docs.triton.one/llms.txt)\ <i class="fa-rss">:rss:</i> Follow updates: [Blog](https://blog.triton.one) · [X](https://x.com/triton_one) · [YouTube](https://www.youtube.com/@triton_one_ltd) · [Telegram](https://t.me/tritonone) · [GitHub](https://github.com/rpcpool)
