1use clap::{Args, Subcommand};
2use serde::Serialize;
3use solana_sdk::{pubkey::Pubkey, signer::Signer};
4use tuktuk_program::cron::{
5 accounts::{CronJobTransactionV0, CronJobV0},
6 types::{AddCronTransactionArgsV0, RemoveCronTransactionArgsV0, TransactionSourceV0},
7};
8use tuktuk_sdk::prelude::*;
9
10use super::{cron::CronArg, TransactionSource};
11use crate::{
12 client::send_instructions,
13 cmd::Opts,
14 result::Result,
15 serde::{print_json, serde_pubkey},
16};
17
18#[derive(Debug, Args)]
19pub struct CronTransactionCmd {
20 #[command(subcommand)]
21 pub cmd: Cmd,
22}
23
24#[derive(Debug, Subcommand)]
25pub enum Cmd {
26 CreateRemote {
27 #[command(flatten)]
28 cron_job: CronArg,
29 #[arg(long)]
30 index: u32,
31 #[arg(long)]
32 url: String,
33 #[arg(long)]
34 signer: Pubkey,
35 },
36 Close {
37 #[command(flatten)]
38 cron_job: CronArg,
39 #[arg(long)]
40 id: u32,
41 },
42 Get {
43 #[command(flatten)]
44 cron_job: CronArg,
45 #[arg(long)]
46 id: u32,
47 },
48 List {
49 #[command(flatten)]
50 cron_job: CronArg,
51 },
52}
53
54impl CronTransactionCmd {
55 pub async fn run(&self, opts: Opts) -> Result<()> {
56 match &self.cmd {
57 Cmd::CreateRemote {
58 cron_job,
59 index,
60 url,
61 signer,
62 } => {
63 let client = opts.client().await?;
64 let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
65 anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
66 })?;
67 let (cron_job_transaction_key, ix) = tuktuk::cron_job_transaction::add_transaction(
68 client.payer.pubkey(),
69 cron_job_key,
70 AddCronTransactionArgsV0 {
71 index: *index,
72 transaction_source: TransactionSourceV0::RemoteV0 {
73 url: url.to_string(),
74 signer: *signer,
75 },
76 },
77 )?;
78 send_instructions(
79 client.rpc_client.clone(),
80 &client.payer,
81 client.opts.ws_url().as_str(),
82 &[ix],
83 &[],
84 )
85 .await?;
86 print_json(&CronTransaction {
87 pubkey: cron_job_transaction_key,
88 id: *index,
89 cron_job: cron_job_key,
90 transaction_source: Some(TransactionSource::RemoteV0 {
91 url: url.to_string(),
92 signer: *signer,
93 }),
94 })?;
95 }
96 Cmd::Close {
97 cron_job,
98 id: index,
99 } => {
100 let client = opts.client().await?;
101 let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
102 anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
103 })?;
104 let cron_job_transaction_key =
105 tuktuk::cron_job_transaction::key(&cron_job_key, *index);
106 let cron_job_transaction: CronJobTransactionV0 = client
107 .rpc_client
108 .anchor_account(&cron_job_transaction_key)
109 .await?
110 .ok_or_else(|| {
111 anyhow::anyhow!(
112 "Cron job transaction not found: {}",
113 cron_job_transaction_key
114 )
115 })?;
116 let ix = tuktuk::cron_job_transaction::remove_transaction(
117 client.payer.pubkey(),
118 cron_job_key,
119 RemoveCronTransactionArgsV0 { index: *index },
120 )?;
121 send_instructions(
122 client.rpc_client.clone(),
123 &client.payer,
124 client.opts.ws_url().as_str(),
125 &[ix],
126 &[],
127 )
128 .await?;
129 print_json(&CronTransaction {
130 pubkey: cron_job_transaction_key,
131 id: *index,
132 cron_job: cron_job_key,
133 transaction_source: Some(TransactionSource::from(to_transaction_source(
134 cron_job_transaction.transaction,
135 ))),
136 })?;
137 }
138 Cmd::Get {
139 cron_job,
140 id: index,
141 } => {
142 let client = opts.client().await?;
143 let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
144 anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
145 })?;
146 let cron_job_transaction_key =
147 tuktuk::cron_job_transaction::key(&cron_job_key, *index);
148 let cron_job_transaction: CronJobTransactionV0 = client
149 .rpc_client
150 .anchor_account(&cron_job_transaction_key)
151 .await?
152 .ok_or_else(|| {
153 anyhow::anyhow!(
154 "Cron job transaction not found: {}",
155 cron_job_transaction_key
156 )
157 })?;
158 print_json(&CronTransaction {
159 pubkey: cron_job_transaction_key,
160 id: *index,
161 cron_job: cron_job_key,
162 transaction_source: Some(TransactionSource::from(to_transaction_source(
163 cron_job_transaction.transaction,
164 ))),
165 })?;
166 }
167 Cmd::List { cron_job } => {
168 let client = opts.client().await?;
169 let cron_job_key = cron_job.get_pubkey(&client).await?.ok_or_else(|| {
170 anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
171 })?;
172 let cron_job: CronJobV0 = client
173 .rpc_client
174 .anchor_account(&cron_job_key)
175 .await?
176 .ok_or_else(|| anyhow::anyhow!("Cron job not found: {}", cron_job_key))?;
177 let cron_job_transaction_keys =
178 tuktuk::cron_job_transaction::keys(&cron_job_key, &cron_job)?;
179 let cron_job_transactions = client
180 .as_ref()
181 .anchor_accounts::<CronJobTransactionV0>(&cron_job_transaction_keys)
182 .await?;
183 print_json(
184 &cron_job_transactions
185 .iter()
186 .map(|(pubkey, maybe_t)| {
187 maybe_t.as_ref().map(|t| CronTransaction {
188 pubkey: *pubkey,
189 id: t.id,
190 cron_job: cron_job_key,
191 transaction_source: Some(TransactionSource::from(
192 to_transaction_source(t.transaction.clone()),
193 )),
194 })
195 })
196 .collect::<Vec<_>>(),
197 )?;
198 }
199 }
200 Ok(())
201 }
202}
203
204fn to_transaction_source(source: TransactionSourceV0) -> tuktuk_program::TransactionSourceV0 {
205 match source {
206 TransactionSourceV0::RemoteV0 { url, signer } => {
207 tuktuk_program::TransactionSourceV0::RemoteV0 { url, signer }
208 }
209 TransactionSourceV0::CompiledV0(transaction) => {
210 tuktuk_program::TransactionSourceV0::CompiledV0(tuktuk_program::CompiledTransactionV0 {
211 num_rw_signers: transaction.num_rw_signers,
212 num_ro_signers: transaction.num_ro_signers,
213 num_rw: transaction.num_rw,
214 accounts: transaction.accounts,
215 instructions: transaction
216 .instructions
217 .into_iter()
218 .map(|i| tuktuk_program::CompiledInstructionV0 {
219 program_id_index: i.program_id_index,
220 accounts: i.accounts,
221 data: i.data,
222 })
223 .collect(),
224 signer_seeds: transaction.signer_seeds,
225 })
226 }
227 }
228}
229
230#[derive(Serialize)]
231pub struct CronTransaction {
232 #[serde(with = "serde_pubkey")]
233 pub pubkey: Pubkey,
234 pub id: u32,
235 #[serde(with = "serde_pubkey")]
236 pub cron_job: Pubkey,
237 pub transaction_source: Option<TransactionSource>,
238}