use crate::api::api;
use crate::error::BittensorError;
use crate::extrinsics::ExtrinsicResponse;
use crate::types::Balance;
use crate::AccountId;
use std::str::FromStr;
use subxt::OnlineClient;
use subxt::PolkadotConfig;
#[derive(Debug, Clone)]
pub struct StakeParams {
pub hotkey: String,
pub netuid: u16,
pub amount_rao: u64,
}
impl StakeParams {
pub fn new_tao(hotkey: &str, netuid: u16, amount_tao: f64) -> Self {
Self {
hotkey: hotkey.to_string(),
netuid,
amount_rao: (amount_tao * 1_000_000_000.0) as u64,
}
}
pub fn new_rao(hotkey: &str, netuid: u16, amount_rao: u64) -> Self {
Self {
hotkey: hotkey.to_string(),
netuid,
amount_rao,
}
}
}
pub async fn add_stake<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
params: StakeParams,
) -> Result<ExtrinsicResponse<Balance>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let hotkey_account =
AccountId::from_str(¶ms.hotkey).map_err(|_| BittensorError::InvalidHotkey {
hotkey: params.hotkey.clone(),
})?;
let call =
api::tx()
.subtensor_module()
.add_stake(hotkey_account, params.netuid, params.amount_rao);
let tx_hash = client
.tx()
.sign_and_submit_default(&call, signer)
.await
.map_err(|e| BittensorError::TxSubmissionError {
message: format!("Failed to submit add_stake: {}", e),
})?;
Ok(ExtrinsicResponse::success()
.with_message("Stake added successfully")
.with_extrinsic_hash(&format!("{:?}", tx_hash))
.with_data(Balance::from_rao(params.amount_rao)))
}
pub async fn remove_stake<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
params: StakeParams,
) -> Result<ExtrinsicResponse<Balance>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let hotkey_account =
AccountId::from_str(¶ms.hotkey).map_err(|_| BittensorError::InvalidHotkey {
hotkey: params.hotkey.clone(),
})?;
let call =
api::tx()
.subtensor_module()
.remove_stake(hotkey_account, params.netuid, params.amount_rao);
let tx_hash = client
.tx()
.sign_and_submit_default(&call, signer)
.await
.map_err(|e| BittensorError::TxSubmissionError {
message: format!("Failed to submit remove_stake: {}", e),
})?;
Ok(ExtrinsicResponse::success()
.with_message("Stake removed successfully")
.with_extrinsic_hash(&format!("{:?}", tx_hash))
.with_data(Balance::from_rao(params.amount_rao)))
}
pub async fn delegate_stake<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
delegate_hotkey: &str,
netuid: u16,
amount_rao: u64,
) -> Result<ExtrinsicResponse<Balance>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let params = StakeParams::new_rao(delegate_hotkey, netuid, amount_rao);
add_stake(client, signer, params).await
}
pub async fn undelegate_stake<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
delegate_hotkey: &str,
netuid: u16,
amount_rao: u64,
) -> Result<ExtrinsicResponse<Balance>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let params = StakeParams::new_rao(delegate_hotkey, netuid, amount_rao);
remove_stake(client, signer, params).await
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stake_params_tao() {
let params =
StakeParams::new_tao("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1, 1.5);
assert_eq!(params.amount_rao, 1_500_000_000);
assert_eq!(params.netuid, 1);
}
#[test]
fn test_stake_params_rao() {
let params =
StakeParams::new_rao("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1, 1000);
assert_eq!(params.amount_rao, 1000);
}
}