Skip to main content

bankr_agent_api/
types.rs

1//! Request and response types for the Bankr Agent API.
2//!
3//! All types are derived from the official API documentation at
4//! <https://docs.bankr.bot/agent-api/overview>.
5
6use serde::{Deserialize, Serialize};
7
8// ---------------------------------------------------------------------------
9// User Info — GET /agent/me
10// ---------------------------------------------------------------------------
11
12/// Wallet entry returned by the `/agent/me` endpoint.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Wallet {
15    /// Chain identifier (`"evm"` or `"solana"`).
16    pub chain: String,
17    /// Wallet address.
18    pub address: String,
19}
20
21/// Social account linked to the user.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct SocialAccount {
24    /// Platform name (e.g. `farcaster`, `twitter`, `telegram`).
25    pub platform: String,
26    /// Username on that platform.
27    pub username: Option<String>,
28}
29
30/// Bankr Club subscription info.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct BankrClub {
34    /// Whether the subscription is active.
35    pub active: bool,
36    /// `"monthly"` or `"yearly"`.
37    pub subscription_type: Option<String>,
38    /// Unix timestamp (ms) of next renewal or cancellation.
39    pub renew_or_cancel_on: Option<u64>,
40}
41
42/// Leaderboard entry.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Leaderboard {
45    /// User score.
46    pub score: u64,
47    /// Leaderboard rank.
48    pub rank: Option<u64>,
49}
50
51/// Successful response from `GET /agent/me`.
52#[derive(Debug, Clone, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct UserInfoResponse {
55    /// Always `true` on success.
56    pub success: bool,
57    /// Wallet addresses.
58    pub wallets: Vec<Wallet>,
59    /// Connected social accounts.
60    pub social_accounts: Vec<SocialAccount>,
61    /// Referral code.
62    pub ref_code: Option<String>,
63    /// Bankr Club subscription info.
64    pub bankr_club: Option<BankrClub>,
65    /// Leaderboard info.
66    pub leaderboard: Option<Leaderboard>,
67}
68
69// ---------------------------------------------------------------------------
70// Prompt — POST /agent/prompt
71// ---------------------------------------------------------------------------
72
73/// Request body for `POST /agent/prompt`.
74#[derive(Debug, Clone, Serialize, Deserialize)]
75#[serde(rename_all = "camelCase")]
76pub struct PromptRequest {
77    /// Natural language command (max 10 000 characters).
78    pub prompt: String,
79    /// Optional thread ID to continue a conversation.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub thread_id: Option<String>,
82}
83
84/// Success response (202 Accepted) from `POST /agent/prompt`.
85#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(rename_all = "camelCase")]
87pub struct PromptResponse {
88    /// Always `true` on success.
89    pub success: bool,
90    /// Unique job identifier.
91    pub job_id: String,
92    /// Conversation thread ID.
93    pub thread_id: String,
94    /// Current status (always `"pending"` on creation).
95    pub status: String,
96    /// Human-readable message.
97    pub message: String,
98}
99
100// ---------------------------------------------------------------------------
101// Job Management — GET /agent/job/{jobId}, POST /agent/job/{jobId}/cancel
102// ---------------------------------------------------------------------------
103
104/// Job status values.
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106#[serde(rename_all = "camelCase")]
107pub enum JobStatus {
108    /// Job is queued for processing.
109    Pending,
110    /// Job is currently being processed.
111    Processing,
112    /// Job finished successfully.
113    Completed,
114    /// Job encountered an error.
115    Failed,
116    /// Job was cancelled by the user.
117    Cancelled,
118}
119
120impl std::fmt::Display for JobStatus {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        match self {
123            Self::Pending => write!(f, "pending"),
124            Self::Processing => write!(f, "processing"),
125            Self::Completed => write!(f, "completed"),
126            Self::Failed => write!(f, "failed"),
127            Self::Cancelled => write!(f, "cancelled"),
128        }
129    }
130}
131
132/// A single status-update entry within a job.
133#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct StatusUpdate {
135    /// Status update message.
136    pub message: Option<String>,
137    /// Timestamp of the update.
138    pub timestamp: Option<String>,
139}
140
141/// Rich data item returned with completed jobs.
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct RichDataItem {
144    /// Type discriminator (e.g. `"token_info"`, `"chart"`).
145    #[serde(rename = "type")]
146    pub kind: String,
147    /// Remaining fields vary by type.
148    #[serde(flatten)]
149    pub extra: serde_json::Value,
150}
151
152/// Response from `GET /agent/job/{jobId}`.
153#[derive(Debug, Clone, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct JobResponse {
156    /// Whether the request succeeded.
157    pub success: bool,
158    /// Job identifier.
159    pub job_id: String,
160    /// Conversation thread ID.
161    pub thread_id: Option<String>,
162    /// Current job status.
163    pub status: JobStatus,
164    /// Original prompt submitted.
165    pub prompt: String,
166    /// ISO 8601 creation timestamp.
167    pub created_at: String,
168    /// Whether the job can still be cancelled.
169    pub cancellable: Option<bool>,
170    /// Progress messages during processing.
171    pub status_updates: Option<Vec<StatusUpdate>>,
172    /// When processing started.
173    pub started_at: Option<String>,
174    /// Agent response text (when completed).
175    pub response: Option<String>,
176    /// Additional structured data (when completed).
177    pub rich_data: Option<Vec<RichDataItem>>,
178    /// When the job finished (completed or failed).
179    pub completed_at: Option<String>,
180    /// Processing duration in milliseconds (when completed).
181    pub processing_time: Option<u64>,
182    /// Error message (when failed).
183    pub error: Option<String>,
184    /// When the job was cancelled.
185    pub cancelled_at: Option<String>,
186}
187
188/// Response from `POST /agent/job/{jobId}/cancel`.
189#[derive(Debug, Clone, Serialize, Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct CancelJobResponse {
192    /// Whether the request succeeded.
193    pub success: bool,
194    /// Job identifier.
195    pub job_id: String,
196    /// Status after cancellation.
197    pub status: String,
198    /// Original prompt.
199    pub prompt: Option<String>,
200    /// Creation timestamp.
201    pub created_at: Option<String>,
202    /// Cancellation timestamp.
203    pub cancelled_at: Option<String>,
204}
205
206// ---------------------------------------------------------------------------
207// Sign — POST /agent/sign
208// ---------------------------------------------------------------------------
209
210/// Signature type discriminator.
211#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
212pub enum SignatureType {
213    /// Standard Ethereum personal-sign.
214    #[serde(rename = "personal_sign")]
215    PersonalSign,
216    /// EIP-712 structured data signing.
217    #[serde(rename = "eth_signTypedData_v4")]
218    EthSignTypedDataV4,
219    /// Sign a transaction without broadcasting.
220    #[serde(rename = "eth_signTransaction")]
221    EthSignTransaction,
222}
223
224impl std::fmt::Display for SignatureType {
225    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226        match self {
227            Self::PersonalSign => write!(f, "personal_sign"),
228            Self::EthSignTypedDataV4 => write!(f, "eth_signTypedData_v4"),
229            Self::EthSignTransaction => write!(f, "eth_signTransaction"),
230        }
231    }
232}
233
234/// EVM transaction parameters used by both sign and submit endpoints.
235#[derive(Debug, Clone, Serialize, Deserialize)]
236#[serde(rename_all = "camelCase")]
237pub struct EvmTransaction {
238    /// Destination address.
239    pub to: String,
240    /// Chain ID.
241    pub chain_id: u64,
242    /// Value in wei (as string).
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub value: Option<String>,
245    /// Calldata (hex string starting with `0x`).
246    #[serde(skip_serializing_if = "Option::is_none")]
247    pub data: Option<String>,
248    /// Gas limit.
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub gas: Option<String>,
251    /// Legacy gas price in wei.
252    #[serde(skip_serializing_if = "Option::is_none")]
253    pub gas_price: Option<String>,
254    /// EIP-1559 max fee per gas.
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub max_fee_per_gas: Option<String>,
257    /// EIP-1559 priority fee.
258    #[serde(skip_serializing_if = "Option::is_none")]
259    pub max_priority_fee_per_gas: Option<String>,
260    /// Transaction nonce.
261    #[serde(skip_serializing_if = "Option::is_none")]
262    pub nonce: Option<u64>,
263}
264
265/// Request body for `POST /agent/sign`.
266///
267/// The body shape depends on `signature_type`:
268/// - `personal_sign` → `message` is required
269/// - `eth_signTypedData_v4` → `typed_data` is required
270/// - `eth_signTransaction` → `transaction` is required
271#[derive(Debug, Clone, Serialize, Deserialize)]
272#[serde(rename_all = "camelCase")]
273pub struct SignRequest {
274    /// The type of signature to produce.
275    pub signature_type: SignatureType,
276    /// Plain text message (for `personal_sign`).
277    #[serde(skip_serializing_if = "Option::is_none")]
278    pub message: Option<String>,
279    /// EIP-712 typed data (for `eth_signTypedData_v4`).
280    #[serde(skip_serializing_if = "Option::is_none")]
281    pub typed_data: Option<serde_json::Value>,
282    /// Transaction to sign (for `eth_signTransaction`).
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub transaction: Option<EvmTransaction>,
285}
286
287/// Success response from `POST /agent/sign`.
288#[derive(Debug, Clone, Serialize, Deserialize)]
289#[serde(rename_all = "camelCase")]
290pub struct SignResponse {
291    /// `true` if signing succeeded.
292    pub success: bool,
293    /// The hex-encoded signature.
294    pub signature: Option<String>,
295    /// Address that produced the signature.
296    pub signer: Option<String>,
297    /// The signature type used.
298    pub signature_type: Option<SignatureType>,
299    /// Error message if signing failed.
300    pub error: Option<String>,
301}
302
303// ---------------------------------------------------------------------------
304// Submit — POST /agent/submit
305// ---------------------------------------------------------------------------
306
307/// Request body for `POST /agent/submit`.
308#[derive(Debug, Clone, Serialize, Deserialize)]
309#[serde(rename_all = "camelCase")]
310pub struct SubmitRequest {
311    /// The transaction to submit.
312    pub transaction: EvmTransaction,
313    /// Human-readable description for logging.
314    #[serde(skip_serializing_if = "Option::is_none")]
315    pub description: Option<String>,
316    /// Wait for on-chain confirmation (default: `true`).
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub wait_for_confirmation: Option<bool>,
319}
320
321/// Response from `POST /agent/submit`.
322#[derive(Debug, Clone, Serialize, Deserialize)]
323#[serde(rename_all = "camelCase")]
324pub struct SubmitResponse {
325    /// `true` if submission succeeded.
326    pub success: bool,
327    /// The transaction hash.
328    pub transaction_hash: Option<String>,
329    /// `"success"`, `"reverted"`, `"pending"`, or `"failed"`.
330    pub status: Option<String>,
331    /// Block number (if confirmed).
332    pub block_number: Option<String>,
333    /// Gas used (if confirmed).
334    pub gas_used: Option<String>,
335    /// Address that signed the transaction.
336    pub signer: Option<String>,
337    /// Chain ID.
338    pub chain_id: Option<u64>,
339    /// Error message if submission failed.
340    pub error: Option<String>,
341}
342
343// ---------------------------------------------------------------------------
344// Common API Error Response
345// ---------------------------------------------------------------------------
346
347/// Standard error envelope returned by the Bankr API.
348#[derive(Debug, Clone, Serialize, Deserialize)]
349#[serde(rename_all = "camelCase")]
350pub struct ApiErrorBody {
351    /// Error type/title.
352    pub error: Option<String>,
353    /// Human-readable error message.
354    pub message: Option<String>,
355    /// When the rate-limit counter resets (Unix ms) — for 429 errors.
356    pub reset_at: Option<u64>,
357    /// Rate-limit quota.
358    pub limit: Option<u64>,
359    /// Number of messages used in the current window.
360    pub used: Option<u64>,
361}