Skip to main content

light_sdk/
error.rs

1use light_account_checks::error::AccountError;
2use light_sdk_types::lca::CompressedAccountError;
3use light_hasher::HasherError;
4use light_sdk_types::error::LightSdkTypesError;
5use thiserror::Error;
6
7use crate::ProgramError;
8
9pub type Result<T> = std::result::Result<T, LightSdkError>;
10
11#[derive(Debug, Error, PartialEq)]
12pub enum LightSdkError {
13    #[error("Constraint violation")]
14    ConstraintViolation,
15    #[error("Invalid light-system-program ID")]
16    InvalidLightSystemProgram,
17    #[error("Expected accounts in the instruction")]
18    ExpectedAccounts,
19    #[error("Expected address Merkle context to be provided")]
20    ExpectedAddressTreeInfo,
21    #[error("Expected address root index to be provided")]
22    ExpectedAddressRootIndex,
23    #[error("Accounts with a specified input are expected to have data")]
24    ExpectedData,
25    #[error("Accounts with specified data are expected to have a discriminator")]
26    ExpectedDiscriminator,
27    #[error("Accounts with specified data are expected to have a hash")]
28    ExpectedHash,
29    #[error("Expected the `{0}` light account to be provided")]
30    ExpectedLightSystemAccount(String),
31    #[error("`mut` and `close` accounts are expected to have a Merkle context")]
32    ExpectedMerkleContext,
33    #[error("Expected root index to be provided")]
34    ExpectedRootIndex,
35    #[error("Cannot transfer lamports from an account without input")]
36    TransferFromNoInput,
37    #[error("Cannot transfer from an account without lamports")]
38    TransferFromNoLamports,
39    #[error("Account, from which a transfer was attempted, has insufficient amount of lamports")]
40    TransferFromInsufficientLamports,
41    #[error("Integer overflow resulting from too large resulting amount")]
42    TransferIntegerOverflow,
43    #[error("Borsh error.")]
44    Borsh,
45    #[error("Fewer accounts than number of system accounts.")]
46    FewerAccountsThanSystemAccounts,
47    #[error("InvalidCpiSignerAccount")]
48    InvalidCpiSignerAccount,
49    #[error("Missing meta field: {0}")]
50    MissingField(String),
51    #[error("Output state tree index is none. Use an CompressedAccountMeta type with output tree index to initialize or update accounts.")]
52    OutputStateTreeIndexIsNone,
53    #[error("Address is none during initialization")]
54    InitAddressIsNone,
55    #[error("Address is none during initialization with address")]
56    InitWithAddressIsNone,
57    #[error("Output is none during initialization with address")]
58    InitWithAddressOutputIsNone,
59    #[error("Address is none during meta mutation")]
60    MetaMutAddressIsNone,
61    #[error("Input is none during meta mutation")]
62    MetaMutInputIsNone,
63    #[error("Output lamports is none during meta mutation")]
64    MetaMutOutputLamportsIsNone,
65    #[error("Output is none during meta mutation")]
66    MetaMutOutputIsNone,
67    #[error("Address is none during meta close")]
68    MetaCloseAddressIsNone,
69    #[error("Input is none during meta close")]
70    MetaCloseInputIsNone,
71    #[error("CPI accounts index out of bounds: {0}")]
72    CpiAccountsIndexOutOfBounds(usize),
73    #[error("Invalid CPI context account")]
74    InvalidCpiContextAccount,
75    #[error("Invalid SolPool PDA account")]
76    InvalidSolPoolPdaAccount,
77    #[error("CpiAccounts accounts slice starts with an invalid account. It should start with LightSystemProgram SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7.")]
78    InvalidCpiAccountsOffset,
79    #[error("Expected LightAccount to have no data for closure.")]
80    ExpectedNoData,
81    #[error("CPI context must be added before any other accounts (next_index must be 0)")]
82    CpiContextOrderingViolation,
83    #[error("Invalid merkle tree index in CPI accounts")]
84    InvalidMerkleTreeIndex,
85    #[error(
86        "Read-only account cannot use to_account_info(), use to_packed_read_only_account() instead"
87    )]
88    ReadOnlyAccountCannotUseToAccountInfo,
89    #[error("Account is not read-only, cannot use to_packed_read_only_account()")]
90    NotReadOnlyAccount,
91    #[error("Read-only accounts are not supported in write_to_cpi_context operations")]
92    ReadOnlyAccountsNotSupportedInCpiContext,
93    #[error(transparent)]
94    AccountError(#[from] AccountError),
95    #[error(transparent)]
96    Hasher(#[from] HasherError),
97    #[error("Program error: {0}")]
98    ProgramError(#[from] ProgramError),
99    #[error("Compressed account error: {0}")]
100    CompressedAccountError(#[from] CompressedAccountError),
101    #[error("Expected tree info to be provided for init_if_needed")]
102    ExpectedTreeInfo,
103    #[error("ExpectedSelfProgram")]
104    ExpectedSelfProgram,
105    #[error("Expected CPI context to be provided")]
106    ExpectedCpiContext,
107    #[error("Account missing compression_info field")]
108    MissingCompressionInfo,
109    #[error("Cannot access compression_info on packed variant")]
110    PackedVariantCompressionInfo,
111    #[error("CToken variant does not support compression_info operations")]
112    CTokenCompressionInfo,
113    #[error("Unexpected unpacked variant during decompression")]
114    UnexpectedUnpackedVariant,
115    #[error("Token variant's prepare() method was called (tokens use separate handling)")]
116    TokenPrepareCalled,
117    #[error("Cannot access compression_info on zero_copy unpacked variant (stores raw bytes)")]
118    ZeroCopyUnpackedVariant,
119    #[error("Rent sponsor account does not match the expected PDA from config")]
120    InvalidRentSponsor,
121}
122
123impl From<LightSdkError> for ProgramError {
124    fn from(e: LightSdkError) -> Self {
125        ProgramError::Custom(e.into())
126    }
127}
128
129/// Convert from SDK's LightSdkError to LightSdkTypesError.
130/// This allows SDK error types to be used where types error types are expected
131/// (e.g., in trait impls for LightPreInit, LightFinalize, AccountMetasVec).
132impl From<LightSdkError> for LightSdkTypesError {
133    fn from(e: LightSdkError) -> Self {
134        match e {
135            LightSdkError::ConstraintViolation => LightSdkTypesError::ConstraintViolation,
136            LightSdkError::Borsh => LightSdkTypesError::Borsh,
137            LightSdkError::AccountError(e) => LightSdkTypesError::AccountError(e),
138            LightSdkError::Hasher(e) => LightSdkTypesError::Hasher(e),
139            LightSdkError::MissingCompressionInfo => LightSdkTypesError::MissingCompressionInfo,
140            LightSdkError::InvalidRentSponsor => LightSdkTypesError::InvalidRentSponsor,
141            LightSdkError::CpiAccountsIndexOutOfBounds(i) => {
142                LightSdkTypesError::CpiAccountsIndexOutOfBounds(i)
143            }
144            LightSdkError::ReadOnlyAccountsNotSupportedInCpiContext => {
145                LightSdkTypesError::ReadOnlyAccountsNotSupportedInCpiContext
146            }
147            LightSdkError::CompressedAccountError(e) => {
148                LightSdkTypesError::CompressedAccountError(e)
149            }
150            LightSdkError::ProgramError(e) => LightSdkTypesError::ProgramError(u64::from(e) as u32),
151            _ => LightSdkTypesError::ConstraintViolation,
152        }
153    }
154}
155
156/// Convert from LightSdkTypesError to SDK's LightSdkError.
157impl From<LightSdkTypesError> for LightSdkError {
158    fn from(e: LightSdkTypesError) -> Self {
159        match e {
160            LightSdkTypesError::InitAddressIsNone => LightSdkError::InitAddressIsNone,
161            LightSdkTypesError::InitWithAddressIsNone => LightSdkError::InitWithAddressIsNone,
162            LightSdkTypesError::InitWithAddressOutputIsNone => {
163                LightSdkError::InitWithAddressOutputIsNone
164            }
165            LightSdkTypesError::MetaMutAddressIsNone => LightSdkError::MetaMutAddressIsNone,
166            LightSdkTypesError::MetaMutInputIsNone => LightSdkError::MetaMutInputIsNone,
167            LightSdkTypesError::MetaMutOutputLamportsIsNone => {
168                LightSdkError::MetaMutOutputLamportsIsNone
169            }
170            LightSdkTypesError::MetaMutOutputIsNone => LightSdkError::MetaMutOutputIsNone,
171            LightSdkTypesError::MetaCloseAddressIsNone => LightSdkError::MetaCloseAddressIsNone,
172            LightSdkTypesError::MetaCloseInputIsNone => LightSdkError::MetaCloseInputIsNone,
173            LightSdkTypesError::FewerAccountsThanSystemAccounts => {
174                LightSdkError::FewerAccountsThanSystemAccounts
175            }
176            LightSdkTypesError::CpiAccountsIndexOutOfBounds(index) => {
177                LightSdkError::CpiAccountsIndexOutOfBounds(index)
178            }
179            LightSdkTypesError::InvalidSolPoolPdaAccount => LightSdkError::InvalidSolPoolPdaAccount,
180            LightSdkTypesError::InvalidCpiContextAccount => LightSdkError::InvalidCpiContextAccount,
181            LightSdkTypesError::InvalidCpiAccountsOffset => LightSdkError::InvalidCpiAccountsOffset,
182            LightSdkTypesError::AccountError(e) => LightSdkError::AccountError(e),
183            LightSdkTypesError::Hasher(e) => LightSdkError::Hasher(e),
184            LightSdkTypesError::ConstraintViolation => LightSdkError::ConstraintViolation,
185            LightSdkTypesError::Borsh => LightSdkError::Borsh,
186            LightSdkTypesError::MissingCompressionInfo => LightSdkError::MissingCompressionInfo,
187            LightSdkTypesError::InvalidRentSponsor => LightSdkError::InvalidRentSponsor,
188            LightSdkTypesError::BorshIo(_) => LightSdkError::Borsh,
189            LightSdkTypesError::ReadOnlyAccountsNotSupportedInCpiContext => {
190                LightSdkError::ReadOnlyAccountsNotSupportedInCpiContext
191            }
192            LightSdkTypesError::CompressedAccountError(e) => {
193                LightSdkError::CompressedAccountError(e)
194            }
195            LightSdkTypesError::AccountDataTooSmall
196            | LightSdkTypesError::InvalidInstructionData
197            | LightSdkTypesError::InvalidSeeds
198            | LightSdkTypesError::CpiFailed
199            | LightSdkTypesError::NotEnoughAccountKeys
200            | LightSdkTypesError::MissingRequiredSignature => LightSdkError::ConstraintViolation,
201            LightSdkTypesError::ProgramError(code) => {
202                LightSdkError::ProgramError(ProgramError::Custom(code))
203            }
204        }
205    }
206}
207
208impl From<LightSdkError> for u32 {
209    fn from(e: LightSdkError) -> Self {
210        match e {
211            LightSdkError::ConstraintViolation => 16001,
212            LightSdkError::InvalidLightSystemProgram => 16002,
213            LightSdkError::ExpectedAccounts => 16003,
214            LightSdkError::ExpectedAddressTreeInfo => 16004,
215            LightSdkError::ExpectedAddressRootIndex => 16005,
216            LightSdkError::ExpectedData => 16006,
217            LightSdkError::ExpectedDiscriminator => 16007,
218            LightSdkError::ExpectedHash => 16008,
219            LightSdkError::ExpectedLightSystemAccount(_) => 16009,
220            LightSdkError::ExpectedMerkleContext => 16010,
221            LightSdkError::ExpectedRootIndex => 16011,
222            LightSdkError::TransferFromNoInput => 16012,
223            LightSdkError::TransferFromNoLamports => 16013,
224            LightSdkError::TransferFromInsufficientLamports => 16014,
225            LightSdkError::TransferIntegerOverflow => 16015,
226            LightSdkError::Borsh => 16016,
227            LightSdkError::FewerAccountsThanSystemAccounts => 16017,
228            LightSdkError::InvalidCpiSignerAccount => 16018,
229            LightSdkError::MissingField(_) => 16019,
230            LightSdkError::OutputStateTreeIndexIsNone => 16020,
231            LightSdkError::InitAddressIsNone => 16021,
232            LightSdkError::InitWithAddressIsNone => 16022,
233            LightSdkError::InitWithAddressOutputIsNone => 16023,
234            LightSdkError::MetaMutAddressIsNone => 16024,
235            LightSdkError::MetaMutInputIsNone => 16025,
236            LightSdkError::MetaMutOutputLamportsIsNone => 16026,
237            LightSdkError::MetaMutOutputIsNone => 16027,
238            LightSdkError::MetaCloseAddressIsNone => 16028,
239            LightSdkError::MetaCloseInputIsNone => 16029,
240            LightSdkError::CpiAccountsIndexOutOfBounds(_) => 16031,
241            LightSdkError::InvalidCpiContextAccount => 16032,
242            LightSdkError::InvalidSolPoolPdaAccount => 16033,
243            LightSdkError::InvalidCpiAccountsOffset => 16034,
244            LightSdkError::ExpectedNoData => 16035,
245            LightSdkError::CpiContextOrderingViolation => 16036,
246            LightSdkError::InvalidMerkleTreeIndex => 16037,
247            LightSdkError::ReadOnlyAccountCannotUseToAccountInfo => 16038,
248            LightSdkError::NotReadOnlyAccount => 16039,
249            LightSdkError::ReadOnlyAccountsNotSupportedInCpiContext => 16040,
250            LightSdkError::AccountError(e) => e.into(),
251            LightSdkError::Hasher(e) => e.into(),
252            LightSdkError::ProgramError(e) => u64::from(e) as u32,
253            LightSdkError::CompressedAccountError(e) => e.into(),
254            LightSdkError::ExpectedTreeInfo => 16041,
255            LightSdkError::ExpectedSelfProgram => 16042,
256            LightSdkError::ExpectedCpiContext => 16043,
257            LightSdkError::MissingCompressionInfo => 16044,
258            LightSdkError::PackedVariantCompressionInfo => 16045,
259            LightSdkError::CTokenCompressionInfo => 16046,
260            LightSdkError::UnexpectedUnpackedVariant => 16047,
261            LightSdkError::TokenPrepareCalled => 16048,
262            LightSdkError::ZeroCopyUnpackedVariant => 16049,
263            LightSdkError::InvalidRentSponsor => 16050,
264        }
265    }
266}