tuktuk-cli 0.2.14

A cli for tuktuk
Documentation
use clap::{Args, Subcommand};
use serde::Serialize;
use solana_sdk::{pubkey::Pubkey, signer::Signer};
use tuktuk_program::cron::{
    accounts::{CronJobTransactionV0, CronJobV0},
    types::{AddCronTransactionArgsV0, RemoveCronTransactionArgsV0, TransactionSourceV0},
};
use tuktuk_sdk::prelude::*;

use super::{cron::CronArg, TransactionSource};
use crate::{
    client::send_instructions,
    cmd::Opts,
    result::Result,
    serde::{print_json, serde_pubkey},
};

#[derive(Debug, Args)]
pub struct CronTransactionCmd {
    #[command(subcommand)]
    pub cmd: Cmd,
}

#[derive(Debug, Subcommand)]
pub enum Cmd {
    CreateRemote {
        #[command(flatten)]
        cron_job: CronArg,
        #[arg(long)]
        index: u32,
        #[arg(long)]
        url: String,
        #[arg(long)]
        signer: Pubkey,
    },
    Close {
        #[command(flatten)]
        cron_job: CronArg,
        #[arg(long)]
        id: u32,
    },
    Get {
        #[command(flatten)]
        cron_job: CronArg,
        #[arg(long)]
        id: u32,
    },
    List {
        #[command(flatten)]
        cron_job: CronArg,
    },
}

impl CronTransactionCmd {
    pub async fn run(&self, opts: Opts) -> Result<()> {
        match &self.cmd {
            Cmd::CreateRemote {
                cron_job,
                index,
                url,
                signer,
            } => {
                let client = opts.client().await?;
                let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
                    anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
                })?;
                let (cron_job_transaction_key, ix) = tuktuk::cron_job_transaction::add_transaction(
                    client.payer.pubkey(),
                    cron_job_key,
                    AddCronTransactionArgsV0 {
                        index: *index,
                        transaction_source: TransactionSourceV0::RemoteV0 {
                            url: url.to_string(),
                            signer: *signer,
                        },
                    },
                )?;
                send_instructions(
                    client.rpc_client.clone(),
                    &client.payer,
                    client.opts.ws_url().as_str(),
                    &[ix],
                    &[],
                )
                .await?;
                print_json(&CronTransaction {
                    pubkey: cron_job_transaction_key,
                    id: *index,
                    cron_job: cron_job_key,
                    transaction_source: Some(TransactionSource::RemoteV0 {
                        url: url.to_string(),
                        signer: *signer,
                    }),
                })?;
            }
            Cmd::Close {
                cron_job,
                id: index,
            } => {
                let client = opts.client().await?;
                let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
                    anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
                })?;
                let cron_job_transaction_key =
                    tuktuk::cron_job_transaction::key(&cron_job_key, *index);
                let cron_job_transaction: CronJobTransactionV0 = client
                    .rpc_client
                    .anchor_account(&cron_job_transaction_key)
                    .await?
                    .ok_or_else(|| {
                        anyhow::anyhow!(
                            "Cron job transaction not found: {}",
                            cron_job_transaction_key
                        )
                    })?;
                let ix = tuktuk::cron_job_transaction::remove_transaction(
                    client.payer.pubkey(),
                    cron_job_key,
                    RemoveCronTransactionArgsV0 { index: *index },
                )?;
                send_instructions(
                    client.rpc_client.clone(),
                    &client.payer,
                    client.opts.ws_url().as_str(),
                    &[ix],
                    &[],
                )
                .await?;
                print_json(&CronTransaction {
                    pubkey: cron_job_transaction_key,
                    id: *index,
                    cron_job: cron_job_key,
                    transaction_source: Some(TransactionSource::from(to_transaction_source(
                        cron_job_transaction.transaction,
                    ))),
                })?;
            }
            Cmd::Get {
                cron_job,
                id: index,
            } => {
                let client = opts.client().await?;
                let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
                    anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
                })?;
                let cron_job_transaction_key =
                    tuktuk::cron_job_transaction::key(&cron_job_key, *index);
                let cron_job_transaction: CronJobTransactionV0 = client
                    .rpc_client
                    .anchor_account(&cron_job_transaction_key)
                    .await?
                    .ok_or_else(|| {
                        anyhow::anyhow!(
                            "Cron job transaction not found: {}",
                            cron_job_transaction_key
                        )
                    })?;
                print_json(&CronTransaction {
                    pubkey: cron_job_transaction_key,
                    id: *index,
                    cron_job: cron_job_key,
                    transaction_source: Some(TransactionSource::from(to_transaction_source(
                        cron_job_transaction.transaction,
                    ))),
                })?;
            }
            Cmd::List { cron_job } => {
                let client = opts.client().await?;
                let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
                    anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
                })?;
                let cron_job: CronJobV0 = client
                    .rpc_client
                    .anchor_account(&cron_job_key)
                    .await?
                    .ok_or_else(|| anyhow::anyhow!("Cron job not found: {}", cron_job_key))?;
                let cron_job_transaction_keys =
                    tuktuk::cron_job_transaction::keys(&cron_job_key, &cron_job)?;
                let cron_job_transactions = client
                    .as_ref()
                    .anchor_accounts::<CronJobTransactionV0>(&cron_job_transaction_keys)
                    .await?;
                print_json(
                    &cron_job_transactions
                        .iter()
                        .map(|(pubkey, maybe_t)| {
                            maybe_t.as_ref().map(|t| CronTransaction {
                                pubkey: *pubkey,
                                id: t.id,
                                cron_job: cron_job_key,
                                transaction_source: Some(TransactionSource::from(
                                    to_transaction_source(t.transaction.clone()),
                                )),
                            })
                        })
                        .collect::<Vec<_>>(),
                )?;
            }
        }
        Ok(())
    }
}

fn to_transaction_source(source: TransactionSourceV0) -> tuktuk_program::TransactionSourceV0 {
    match source {
        TransactionSourceV0::RemoteV0 { url, signer } => {
            tuktuk_program::TransactionSourceV0::RemoteV0 { url, signer }
        }
        TransactionSourceV0::CompiledV0(transaction) => {
            tuktuk_program::TransactionSourceV0::CompiledV0(tuktuk_program::CompiledTransactionV0 {
                num_rw_signers: transaction.num_rw_signers,
                num_ro_signers: transaction.num_ro_signers,
                num_rw: transaction.num_rw,
                accounts: transaction.accounts,
                instructions: transaction
                    .instructions
                    .into_iter()
                    .map(|i| tuktuk_program::CompiledInstructionV0 {
                        program_id_index: i.program_id_index,
                        accounts: i.accounts,
                        data: i.data,
                    })
                    .collect(),
                signer_seeds: transaction.signer_seeds,
            })
        }
    }
}

#[derive(Serialize)]
pub struct CronTransaction {
    #[serde(with = "serde_pubkey")]
    pub pubkey: Pubkey,
    pub id: u32,
    #[serde(with = "serde_pubkey")]
    pub cron_job: Pubkey,
    pub transaction_source: Option<TransactionSource>,
}