cambrian_rust_sdk/
lib.rs

1//! Cambrian Rust SDK - Type definitions and utilities for Cambrian AVS (Actively Validated Services) payloads
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use serde_repr::Serialize_repr;
6use solana_program::instruction::Instruction;
7
8/// Account roles for Cambrian payload instructions with bitflag representation
9/// 
10/// Bitflag guide: is signer ⌄⌄ is writable
11#[derive(Serialize_repr)]
12#[repr(u8)]
13pub enum AccountRole {
14    WritableSigner = 0b11,
15    ReadonlySigner = 0b10,
16    Writable = 0b01,
17    Readonly = 0b00,
18}
19
20/// Input structure from CAMB_INPUT environment variable
21#[derive(Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct Input {
24    /// Name of the Proof of Authority
25    pub poa_name: String,
26    pub proposal_storage_key: String,
27}
28
29/// Account metadata for a Cambrian payload instruction
30#[derive(Serialize)]
31#[serde(rename_all = "camelCase")]
32pub struct AccountMeta {
33    pub address: String,
34    pub role: AccountRole,
35}
36
37/// Cambrian proposal instruction format
38#[derive(Serialize)]
39#[serde(rename_all = "camelCase")]
40pub struct ProposalInstruction {
41    pub program_address: String,
42    pub accounts: Vec<AccountMeta>,
43    pub data: Vec<u8>,
44}
45
46/// Complete response output for a Cambrian payload
47#[derive(Serialize)]
48#[serde(rename_all = "camelCase")]
49pub struct Response {
50    /// List of instructions to be included in the proposal
51    pub proposal_instructions: Vec<ProposalInstruction>,
52}
53
54impl Response {
55    /// Serializes the response to a JSON string for output
56    /// 
57    /// Returns a properly formatted JSON string or an error
58    pub fn to_output_ix(&self) -> Result<String> {
59        Ok(serde_json::to_string_pretty(&self)?)
60    }
61}
62
63impl From<Instruction> for ProposalInstruction {
64    fn from(value: Instruction) -> Self {
65        ProposalInstruction {
66            program_address: value.program_id.to_string(),
67            accounts: value
68                .accounts
69                .into_iter()
70                .map(|meta| AccountMeta {
71                    address: meta.pubkey.to_string(),
72                    role: (meta.is_writable, meta.is_signer).into(),
73                })
74                .collect(),
75            data: value.data,
76        }
77    }
78}
79
80impl From<&Instruction> for ProposalInstruction {
81    fn from(value: &Instruction) -> Self {
82        ProposalInstruction {
83            program_address: value.program_id.to_string(),
84            accounts: value
85                .accounts
86                .iter()
87                .map(|meta| AccountMeta {
88                    address: meta.pubkey.to_string(),
89                    role: (meta.is_writable, meta.is_signer).into(),
90                })
91                .collect(),
92            data: value.data.clone(),
93        }
94    }
95}
96
97impl From<&[Instruction]> for Response {
98    fn from(value: &[Instruction]) -> Self {
99        Response {
100            proposal_instructions: value.iter().map(Into::into).collect(),
101        }
102    }
103}
104
105impl From<Instruction> for Response {
106    fn from(value: Instruction) -> Self {
107        Response {
108            proposal_instructions: vec![value.into()],
109        }
110    }
111}
112
113impl From<&Instruction> for Response {
114    fn from(value: &Instruction) -> Self {
115        Response {
116            proposal_instructions: vec![value.into()],
117        }
118    }
119}
120
121impl From<Vec<Instruction>> for Response {
122    fn from(value: Vec<Instruction>) -> Self {
123        Response {
124            proposal_instructions: value.into_iter().map(Into::into).collect(),
125        }
126    }
127}
128
129
130impl From<(bool, bool)> for AccountRole {
131    fn from((is_writable, is_signer): (bool, bool)) -> Self {
132        match (is_writable, is_signer) {
133            (false, false) => AccountRole::Readonly,
134            (false, true) => AccountRole::ReadonlySigner,
135            (true, false) => AccountRole::Writable,
136            (true, true) => AccountRole::WritableSigner,
137        }
138    }
139}