Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
861 changes: 529 additions & 332 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jito-priority-fee-distribution = { features = ["no-entrypoint"], git = "https://
jito-steward = { path = "programs/steward", features = ["no-entrypoint"] }
jito-tip-distribution = { features = ["no-entrypoint"], git = "https://github.com/jito-foundation/jito-programs", branch = "master" }
jito-tip-distribution-sdk = { git = "https://github.com/jito-foundation/jito-programs", branch = "master" }
kobe-client = "0.1.6"
log = "0.4.18"
reqwest = { version = "0.11.27", features = ["json"] }
serde = "1.0.183"
Expand Down
1 change: 1 addition & 0 deletions keepers/stakenet-keeper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jito-priority-fee-distribution = { features = ["no-entrypoint"], workspace = tru
jito-steward = { features = ["no-entrypoint"], path = "../../programs/steward" }
jito-tip-distribution = { features = ["no-entrypoint"], workspace = true }
jito-tip-distribution-sdk = { workspace = true }
kobe-client = { workspace = true }
log = "0.4.18"
rand = "0.8.5"
regex = "1.10"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::sync::Arc;

use kobe_client::client::KobeClient;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_pubkey::Pubkey;
use solana_sdk::{signature::Keypair, signer::Signer};
Expand All @@ -9,7 +10,7 @@ use stakenet_sdk::{
submit_stats::SubmitStats,
},
utils::{
instructions::compute_directed_stake_meta,
instructions::{compute_bam_targets, compute_directed_stake_meta},
transactions::{package_instructions, submit_packaged_transactions},
},
};
Expand All @@ -22,10 +23,11 @@ pub(crate) async fn crank_copy_directed_stake_targets(
all_steward_accounts: &AllStewardAccounts,
token_mint_address: &Pubkey,
priority_fee: Option<u64>,
kobe_client: &KobeClient,
) -> Result<SubmitStats, JitoTransactionError> {
let mut stats = SubmitStats::default();

let ixs = compute_directed_stake_meta(
let mut ixs = compute_directed_stake_meta(
client.clone(),
token_mint_address,
&all_steward_accounts.stake_pool_address,
Expand All @@ -36,6 +38,18 @@ pub(crate) async fn crank_copy_directed_stake_targets(
.await
.map_err(|e| JitoTransactionError::Custom(e.to_string()))?;

let bam_ixs = compute_bam_targets(
client.clone(),
kobe_client,
&all_steward_accounts.config_address,
&keypair.pubkey(),
program_id,
)
.await
.map_err(|e| JitoTransactionError::Custom(e.to_string()))?;

ixs.extend(bam_ixs);

log::info!("Copy Directed Stake Targets");

let update_txs_to_run = package_instructions(&ixs, 8, priority_fee, Some(1_400_000), None);
Expand Down
9 changes: 9 additions & 0 deletions keepers/stakenet-keeper/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ It will emits metrics for each data feed, if env var SOLANA_METRICS_CONFIG is se
*/
use clap::Parser;
use dotenvy::dotenv;
use kobe_client::client::KobeClient;
use log::*;
use rand::Rng;
use rusqlite::Connection;
Expand All @@ -23,6 +24,7 @@ use stakenet_keeper::{
update_state::{create_missing_accounts, post_create_update, pre_create_update},
},
};
use stakenet_sdk::models::cluster::Cluster;
use std::{process::Command, sync::Arc, time::Duration};
use tokio::sync::Mutex;
use tokio::time::sleep;
Expand Down Expand Up @@ -357,6 +359,12 @@ fn main() {
})
.expect("Failed to create socket addresses from gossip entrypoints");

let kobe_client = match args.cluster {
Cluster::Mainnet => KobeClient::mainnet(),
Cluster::Testnet => KobeClient::testnet(),
_ => panic!("Failed to read cluster"),
};

let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async {
let hostname_cmd = Command::new("hostname")
Expand Down Expand Up @@ -436,6 +444,7 @@ fn main() {
lookback_epochs: args.lookback_epochs,
lookback_start_offset_epochs: args.lookback_start_offset_epochs,
validator_history_min_stake: args.validator_history_min_stake,
kobe_client,
};

run_keeper(config).await;
Expand Down
1 change: 1 addition & 0 deletions keepers/stakenet-keeper/src/operations/steward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ pub async fn run_crank_steward(
steward_accounts,
&keeper_config.token_mint,
Some(keeper_config.priority_fee_in_microlamports),
&keeper_config.kobe_client,
)
.await?;

Expand Down
4 changes: 4 additions & 0 deletions keepers/stakenet-keeper/src/state/keeper_config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{fmt, net::SocketAddr, path::PathBuf, sync::Arc};

use clap::{arg, command, Parser};
use kobe_client::client::KobeClient;
use rusqlite::Connection;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
Expand Down Expand Up @@ -46,6 +47,9 @@ pub struct KeeperConfig {

/// Minimum activated stake threshold for creating validator history accounts (in lamports)
pub validator_history_min_stake: u64,

/// A client for interacting with kobe api
pub kobe_client: KobeClient,
}

impl KeeperConfig {
Expand Down
1 change: 1 addition & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ clap = { version = "4.3.0", features = ["derive"] }
futures = "0.3.21"
jito-steward = { features = ["no-entrypoint"], path = "../programs/steward" }
jito-tip-distribution = { features = ["no-entrypoint"], workspace = true }
kobe-client = { workspace = true }
log = "0.4.18"
solana-account-decoder = { workspace = true }
solana-client = { workspace = true }
Expand Down
112 changes: 111 additions & 1 deletion sdk/src/utils/instructions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{collections::HashMap, sync::Arc};
use std::{collections::HashMap, str::FromStr, sync::Arc};

use anchor_lang::{InstructionData, ToAccountMetas};
use jito_steward::DirectedStakePreference;
use kobe_client::client::KobeClient;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
instruction::Instruction,
Expand Down Expand Up @@ -170,3 +171,112 @@ pub async fn compute_directed_stake_meta(
.collect();
Ok(instructions)
}

// FIXME: Create temp response type from Kobe Client
#[allow(dead_code)]
struct BamValidator {
active_stake: u64,
epoch: u64,
identity_account: String,
is_eligible: bool,
ineligibility_reason: Option<String>,
vote_account: String,
}

// FIXME: Create temp response type from Kobe Client
#[allow(dead_code)]
struct BamEpochMetric {
allocation_bps: u64,
available_bam_delegation_stake: u64,
bam_stake: u64,
eligible_bam_validator_count: u64,
epoch: u64,
jitosol_stake: u64,
total_stake: u64,
}

/// Computes directed stake for bam delegation
///
/// This function performs a calculation of stake delegation targets across all BAM validators
/// based on response from Kobe API.
///
/// # Process Overview
///
/// 1. Fetches all bam validators
/// 2. For each eligible bam validaotr:
/// - Calculate total targets ((Current BAM active stake / Total stake amount of Eligible validators) * BAM available bam delegation stake amount)
/// 3. Generates `CopyDirectedStakeTargets` instructions for each eligible BAM validator
pub async fn compute_bam_targets(
client: Arc<RpcClient>,
_kobe_client: &KobeClient,
steward_config: &Pubkey,
authority_pubkey: &Pubkey,
program_id: &Pubkey,
) -> Result<Vec<Instruction>, JitoInstructionError> {
let epoch_info = client.get_epoch_info().await?;
let _last_epoch = epoch_info.epoch - 1;

// FIXME: get response from kobe api
let bam_validators = vec![
BamValidator {
active_stake: 152458755252594,
epoch: 881,
identity_account: "BxkAkLR2W3agWtjMXBNvhxmB8vsn7zhjNQcyfost99KY".to_string(),
is_eligible: true,
ineligibility_reason: None,
vote_account: "FSDKGroWxgBf7VmV6X1NLDhnncrWW2ekztwRWiJrPf3k".to_string(),
},
BamValidator {
active_stake: 184516161965281,
epoch: 881,
identity_account: "6xUK9Nbonr4eoJNtHGoUEMmYKoPz5mipKzyDBv6deX4d".to_string(),
is_eligible: true,
ineligibility_reason: None,
vote_account: "8vyuJTHSDkx7k1zymea4TMsgvixf3rCYBXHPDQajePkE".to_string(),
},
];

// FIXME: get response from kobe api
let bam_epoch_metric = BamEpochMetric {
allocation_bps: 2000,
epoch: 881,
available_bam_delegation_stake: 2824663853562698,
bam_stake: 9681152794462484,
eligible_bam_validator_count: 44,
jitosol_stake: 14123319267813492,
total_stake: 413389737234469800,
};

let directed_stake_meta_pda = get_directed_stake_meta_address(steward_config, program_id);

let bam_eligible_validators: Vec<BamValidator> = bam_validators
.into_iter()
.filter(|bv| bv.is_eligible)
.collect();

let instructions = bam_eligible_validators
.iter()
.filter_map(|bv| {
let vote_pubkey = Pubkey::from_str(&bv.vote_account).ok()?;
let total_target_lamports = (bv.active_stake / bam_epoch_metric.bam_stake)
* bam_epoch_metric.available_bam_delegation_stake;

Some(Instruction {
program_id: *program_id,
accounts: jito_steward::accounts::CopyDirectedStakeTargets {
config: *steward_config,
directed_stake_meta: directed_stake_meta_pda,
authority: *authority_pubkey,
clock: solana_sdk::sysvar::clock::id(),
}
.to_account_metas(None),
data: jito_steward::instruction::CopyDirectedStakeTargets {
vote_pubkey,
total_target_lamports,
}
.data(),
})
})
.collect();
Ok(instructions)
}
1 change: 1 addition & 0 deletions utils/steward-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dotenvy = { workspace = true }
futures = "0.3.21"
futures-util = "0.3.21"
jito-steward = { features = ["no-entrypoint"], path = "../../programs/steward" }
kobe-client = { workspace = true }
log = "0.4.18"
serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ use std::{
use anchor_lang::AccountDeserialize;
use anyhow::{anyhow, Result};
use clap::Parser;
use kobe_client::client::KobeClient;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
pubkey::Pubkey, signature::read_keypair_file, signer::Signer, transaction::Transaction,
};
use stakenet_sdk::utils::{
accounts::{get_all_steward_accounts, get_directed_stake_tickets},
helpers::get_token_balance,
instructions::compute_directed_stake_meta,
instructions::{compute_bam_targets, compute_directed_stake_meta},
};

use crate::{
Expand All @@ -49,9 +50,13 @@ pub struct ComputeDirectedStakeMeta {
#[command(flatten)]
permissioned_parameters: PermissionedParameters,

// Jito SOL Token mint address
/// Jito SOL Token mint address
#[arg(long, env)]
pub token_mint: Pubkey,

/// Cluster name
#[arg(long, env)]
pub cluster_name: String,
}

/// Computes directed stake metadata by aggregating tickets and token balances.
Expand Down Expand Up @@ -167,7 +172,7 @@ pub async fn command_crank_compute_directed_stake_meta(
let all_steward_accounts =
get_all_steward_accounts(client, &program_id, &steward_config).await?;

let ixs = compute_directed_stake_meta(
let mut ixs = compute_directed_stake_meta(
client.clone(),
&args.token_mint,
&all_steward_accounts.stake_pool_address,
Expand All @@ -178,6 +183,23 @@ pub async fn command_crank_compute_directed_stake_meta(
.await
.map_err(|e| anyhow!(e.to_string()))?;

let kobe_client = match args.cluster_name.as_str() {
"mainnet" => KobeClient::mainnet(),
"testnet" => KobeClient::testnet(),
_ => return Err(anyhow!("Failed to read cluster")),
};
let bam_ixs = compute_bam_targets(
client.clone(),
&kobe_client,
&all_steward_accounts.config_address,
&signer,
&program_id,
)
.await
.map_err(|e| anyhow!(e.to_string()))?;

ixs.extend(bam_ixs);

let configured_ix = configure_instruction(
&ixs,
args.permissioned_parameters
Expand Down
Loading