Skip to main content

light_sdk/
error.rs

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