Skip to content

Commit dad0d5a

Browse files
committed
Add policy store lib for accessing policies in transaction forwarders
1 parent 7faa9c0 commit dad0d5a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+4496
-2138
lines changed

β€ŽCargo.lockβ€Ž

Lines changed: 1384 additions & 1750 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€ŽCargo.tomlβ€Ž

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11

22
[workspace]
33
resolver = "2"
4-
members = ["cli", "clients/rust", "program"]
4+
members = ["cli", "clients/rust", "parser", "program", "store"]
55

66
[workspace.dependencies]
77
yellowstone-shield-client = { path = "clients/rust" }
88
yellowstone-shield = { path = "program" }
9+
yellowstone-shield-cli = { path = "cli" }
10+
yellowstone-shield-parser = { path = "parser" }
911
anyhow = "1.0.97"
12+
solana-sdk = "~2.1.11"
13+
solana-program = "~2.1.11"
14+
15+
[workspace.metadata.patch.crates-io]
16+
solana-program = { git = "https://github.com/rpcpool/solana-public.git", tag = "v2.1.11-triton-public" }
17+
solana-sdk = { git = "https://github.com/rpcpool/solana-public.git", tag = "v2.1.11-triton-public" }

β€ŽREADME.mdβ€Ž

Lines changed: 7 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Yellowstone Shield is a Solana program designed to manage allowlists and blockli
1919
- Supports updates via websocket/gRPC.
2020
- Overcomes limitations of Solana's ALTs and Config programs.
2121

22-
## Integration
22+
## Solana RPC Integration
2323

2424
Yellowstone Shield integrates with Solana RPC by introducing:
2525

@@ -47,6 +47,10 @@ A CLI tool is provided for convenient management of Yellowstone Shield policies,
4747

4848
This CLI allows creating policies, adding or removing validators, and managing configurations directly via terminal commands.
4949

50+
## Rust Policy Store
51+
52+
The Rust Policy Store provides efficient caching and quick retrieval of Yellowstone Shield policies, enabling real-time validator permission checks in transaction forwarders and RPC services. It ensures thread-safe access and updates with atomic snapshots. See the [Policy Store README](./policy-store/README.md) for detailed integration and usage instructions.
53+
5054
## Policy Bound to Token Extensions Asset
5155

5256
Policies are bound to a Token Extensions (TE) asset. Token holders can update validator identities tracked by the policy. The TE asset also contains metadata describing the policy:
@@ -55,91 +59,13 @@ Policies are bound to a Token Extensions (TE) asset. Token holders can update va
5559
- **Symbol**: Short representation of the policy.
5660
- **URI**: Link to additional policy information.
5761

58-
### Binding Policy to Token Extensions Asset
59-
6062
The policy account uses a Program Derived Address (PDA), derived with the seed:
6163

6264
```
6365
["shield", "policy", {mint_address}]
6466
```
6567

66-
Here, `{mint_address}` is the mint address of the associated Token Extensions asset.
67-
68-
---
69-
70-
## Program State
71-
72-
### Policy Account
73-
74-
Each policy account stores:
75-
76-
- `kind`: Always set to `Policy`.
77-
- `strategy`: Either `Allow` or `Deny`.
78-
- `validatorIdentities`: Validator public keys.
79-
80-
## Instructions
81-
82-
### CreatePolicy
83-
84-
Creates a policy account.
85-
86-
**Accounts:**
87-
88-
- `mint`: Token mint for policy management.
89-
- `tokenAccount`: Authority token account.
90-
- `policy`: Policy account (mutable).
91-
- `payer`: Fee-paying account (mutable, signer).
92-
- `systemProgram`: System program.
93-
- `tokenProgram`: SPL token program.
94-
95-
**Arguments:**
96-
97-
- `strategy`: `Allow` or `Deny`.
98-
- `validatorIdentities`: Validator public keys.
99-
100-
### AddIdentity
101-
102-
Adds a validator to a policy.
103-
104-
**Accounts:**
105-
106-
- `mint`: Token mint.
107-
- `tokenAccount`: Authority account.
108-
- `policy`: Policy account (mutable).
109-
- `payer`: Fee-paying account (mutable, signer).
110-
- `systemProgram`: System program.
111-
112-
**Arguments:**
113-
114-
- `validatorIdentity`: Validator public key.
115-
116-
### RemoveIdentity
117-
118-
Removes a validator from a policy.
119-
120-
**Accounts:**
121-
122-
- `mint`: Token mint.
123-
- `tokenAccount`: Authority account.
124-
- `policy`: Policy account (mutable).
125-
- `payer`: Fee-paying account (mutable, signer).
126-
- `systemProgram`: System program.
127-
128-
**Arguments:**
129-
130-
- `validatorIdentity`: Validator public key.
131-
132-
## Errors
133-
134-
Common errors:
135-
136-
- `DeserializationError`
137-
- `SerializationError`
138-
- `InvalidPda`
139-
- `ValidatorIdentityNotFound`
140-
- `InvalidAssociatedTokenAccount`
141-
142-
## Development Setup
68+
## Development
14369

14470
Install dependencies:
14571

@@ -177,4 +103,4 @@ AGPL-3.0
177103

178104
## Developers
179105

180-
This project is developded by [Triton One](https://triton.one/).
106+
This project is developed by [Triton One](https://triton.one/).

β€Žcli/Cargo.tomlβ€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
[package]
2-
name = "cli"
2+
name = "yellowstone-shield-cli"
33
version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
77
clap = "4.5.32"
88
clap_derive = "4.5.32"
9-
yellowstone-shield-client = { workspace = true }
9+
yellowstone-shield-client = { workspace = true, features = [
10+
"token-extensions",
11+
] }
1012
solana-sdk = "2.1.11"
1113
solana-cli = "2.1.11"
1214
solana-cli-config = "2.1.11"

β€Žcli/src/command/mod.rsβ€Ž

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
pub mod policy;
22
pub mod validator;
33

4-
use crate::CommandContext;
54
use anyhow::Result;
5+
use solana_client::nonblocking::rpc_client::RpcClient;
6+
use solana_sdk::pubkey::Pubkey;
7+
use solana_sdk::signature::Keypair;
8+
use spl_token_metadata_interface::state::TokenMetadata;
9+
use yellowstone_shield_client::accounts::Policy;
10+
11+
pub struct CommandContext {
12+
pub client: RpcClient,
13+
pub keypair: Keypair,
14+
}
15+
16+
pub struct SolanaAccount<T>(pub Pubkey, pub T);
17+
pub struct CommandComplete(pub SolanaAccount<TokenMetadata>, pub SolanaAccount<Policy>);
18+
19+
pub type RunResult = Result<CommandComplete>;
620

721
#[async_trait::async_trait]
822
pub trait RunCommand {
9-
async fn run(&self, context: CommandContext) -> Result<()>;
23+
async fn run(&self, context: CommandContext) -> RunResult;
1024
}

β€Žcli/src/command/policy.rsβ€Ž

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use anyhow::Result;
22
use log::info;
33
use solana_sdk::{
44
account::WritableAccount,
5+
commitment_config::CommitmentConfig,
6+
native_token::Sol,
57
pubkey::Pubkey,
68
signature::{Keypair, Signer},
79
};
@@ -22,13 +24,13 @@ use yellowstone_shield_client::{
2224
TransactionBuilder,
2325
};
2426

25-
use super::RunCommand;
26-
use crate::CommandContext;
27+
use super::{RunCommand, RunResult};
28+
use crate::command::{CommandComplete, CommandContext, SolanaAccount};
2729
use borsh::BorshDeserialize;
2830

2931
/// Builder for creating a new policy
3032
pub struct CreateCommandBuilder<'a> {
31-
strategy: Option<&'a PermissionStrategy>,
33+
strategy: Option<PermissionStrategy>,
3234
validator_identities: Option<&'a Vec<Pubkey>>,
3335
name: Option<String>,
3436
symbol: Option<String>,
@@ -48,7 +50,7 @@ impl<'a> CreateCommandBuilder<'a> {
4850
}
4951

5052
/// Set the strategy for the policy
51-
pub fn strategy(mut self, strategy: &'a PermissionStrategy) -> Self {
53+
pub fn strategy(mut self, strategy: PermissionStrategy) -> Self {
5254
self.strategy = Some(strategy);
5355
self
5456
}
@@ -81,7 +83,7 @@ impl<'a> CreateCommandBuilder<'a> {
8183
#[async_trait::async_trait]
8284
impl<'a> RunCommand for CreateCommandBuilder<'a> {
8385
/// Execute the creation of the policy
84-
async fn run(&self, context: CommandContext) -> Result<()> {
86+
async fn run(&self, context: CommandContext) -> RunResult {
8587
let CommandContext { keypair, client } = context;
8688

8789
// Given a PDA derived from the payer's public key.
@@ -150,7 +152,7 @@ impl<'a> RunCommand for CreateCommandBuilder<'a> {
150152
.payer(keypair.pubkey())
151153
.token_account(payer_token_account)
152154
.validator_identities(validator_identities.to_vec())
153-
.strategy(yellowstone_shield_client::types::PermissionStrategy::Allow)
155+
.strategy(self.strategy.expect("strategy must be set"))
154156
.instruction();
155157

156158
// Initialize the payer's token account.
@@ -185,7 +187,10 @@ impl<'a> RunCommand for CreateCommandBuilder<'a> {
185187
.transaction();
186188

187189
client
188-
.send_and_confirm_transaction_with_spinner(&tx)
190+
.send_and_confirm_transaction_with_spinner_and_commitment(
191+
&tx,
192+
CommitmentConfig::confirmed(),
193+
)
189194
.await?;
190195

191196
let mut account_data = client.get_account(&address).await?;
@@ -200,26 +205,9 @@ impl<'a> RunCommand for CreateCommandBuilder<'a> {
200205
let mut mint_bytes = mint_pod.get_extension_bytes::<TokenMetadata>().unwrap();
201206
let token_metadata = TokenMetadata::try_from_slice(&mut mint_bytes).unwrap();
202207

203-
info!("πŸŽ‰ Policy successfully created! πŸŽ‰");
204-
info!("--------------------------------");
205-
info!("🏠 Addresses:");
206-
info!(" πŸ“œ Policy: {}", address);
207-
info!(" πŸ”‘ Mint: {}", mint.pubkey());
208-
info!("--------------------------------");
209-
info!("πŸ” Details:");
210-
match policy.strategy {
211-
PermissionStrategy::Allow => info!(" βœ… Strategy: Allow"),
212-
PermissionStrategy::Deny => info!(" ❌ Strategy: Deny"),
213-
}
214-
info!(
215-
" πŸ›‘οΈ Validator Identities: {:?}",
216-
policy.validator_identities
217-
);
218-
info!(" 🏷️ Name: {}", token_metadata.name);
219-
info!(" πŸ”– Symbol: {}", token_metadata.symbol);
220-
info!(" 🌐 URI: {}", token_metadata.uri);
221-
info!("--------------------------------");
222-
223-
Ok(())
208+
Ok(CommandComplete(
209+
SolanaAccount(mint.pubkey(), token_metadata),
210+
SolanaAccount(address, policy),
211+
))
224212
}
225213
}

0 commit comments

Comments
Β (0)