cow_settlement_interface/error.rs
1//! Program-side errors surfaced by the settlement program.
2
3/// Program-side errors surfaced by the settlement program.
4/// The discriminant value is the on-chain `ProgramError::Custom` code.
5#[derive(Clone, Copy, Debug, Eq, PartialEq, num_enum::TryFromPrimitive)]
6#[repr(u32)]
7pub enum SettlementError {
8 /// The `FinalizeSettle` included as input to `BeginSettle` isn't before
9 /// the actual `BeginSettle` index.
10 FinalizeBeforeInitialize = 0,
11 /// Another `BeginSettle`/`FinalizeSettle` of this program appears strictly
12 /// between this pair's bounds, nesting or overlapping two settlements.
13 BeginFinalizePairOverlap = 1,
14 /// The counterpart index points past the end of the transaction's
15 /// instruction list, so no instruction sits there.
16 MissingCounterpartInstruction = 2,
17 /// The instruction at the counterpart index belongs to a different program.
18 CounterpartIsExternal = 3,
19 /// The counterpart instruction's discriminator byte couldn't be recovered
20 /// from its data.
21 InvalidCounterpartDiscriminator = 4,
22 /// The counterpart instruction's own counterpart index couldn't be
23 /// recovered from its data.
24 InvalidCounterpartCounterpart = 5,
25 /// The counterpart's discriminator isn't the expected
26 /// `BeginSettle`/`FinalizeSettle` kind, or its counterpart index doesn't
27 /// point back at this instruction.
28 MismatchedCounterpartDiscriminator = 6,
29 /// An order-creation instruction's intent owner isn't the owner it must
30 /// have: the signer for `CreateOrder`, the settlement state PDA for
31 /// `CreateSettlementOwnedOrder`.
32 OwnerMismatch = 7,
33 /// An account was provided that cannot be derived from the seeds recognized by the program
34 AccountNotDerivable = 8,
35 /// `BeginSettle`'s order accounts aren't passed strictly increasing by
36 /// address.
37 OrdersNotStrictlyIncreasing = 9,
38 /// A `BeginSettle` sell token account doesn't match the
39 /// `sell_token_account` recorded in the order's intent.
40 SellTokenAccountMismatch = 10,
41 /// A `BeginSettle` sell token account isn't a valid SPL token account
42 /// (wrong data length or not owned by the token program).
43 SellTokenAccountInvalid = 11,
44 /// A `BeginSettle` sell token account's SPL owner isn't the order's intent
45 /// owner.
46 SellTokenOwnerMismatch = 12,
47 /// `BeginSettle`'s order-account count doesn't match the structure its
48 /// instruction data expects: `n` orders each contribute an order PDA, a
49 /// sell token account, a sell mint, plus one destination account per
50 /// transfer.
51 AccountCountNotMatchingOrderCount = 13,
52 /// `BeginSettle` or `FinalizeSettle` was invoked via CPI rather than as a
53 /// top-level transaction instruction.
54 CalledViaCpi = 14,
55 /// A `BeginSettle` order has been cancelled by its owner and can no longer
56 /// be settled.
57 OrderCancelled = 15,
58 /// A `BeginSettle` order's `valid_to` lies in the past: the order has
59 /// expired and can no longer be settled.
60 OrderExpired = 16,
61 /// The transfer counts in `BeginSettle` don't sum to the number of transfer
62 /// amounts, so destinations and amounts can't be paired up exactly.
63 TransferCountMismatch = 17,
64 /// `BeginSettle`'s state account isn't the canonical settlement state PDA,
65 /// which must sign the pulls as the user's token delegate.
66 StateAccountMismatch = 18,
67 /// `FinalizeSettle`'s push-account count doesn't match its instruction
68 /// data: each push contributes a source buffer, a destination, and a mint,
69 /// so the count must be three times the number of push amounts.
70 AccountCountNotMatchingPushCount = 19,
71 /// `BeginSettle`: the number of pushes carried by the paired `FinalizeSettle`
72 /// doesn't equal the number of settled orders. Each order must be paid by
73 /// exactly one push.
74 SettledOrderPushCountMismatch = 20,
75 /// `BeginSettle`: a paired `FinalizeSettle` push doesn't send its proceeds
76 /// to the order's buy token account; its destination differs from the
77 /// `buy_token_account` in the order's intent.
78 PushDestinationMismatch = 21,
79 /// `BeginSettle`: a paired `FinalizeSettle` push doesn't draw funds from the
80 /// canonical buffer for the order's `buy_mint`.
81 PushSourceNotBuffer = 22,
82 /// `BeginSettle`: the OrderIntent `sell_token_account` holds a different
83 /// mint than the declared `sell_mint`.
84 SellMintMismatch = 23,
85 /// `BeginSettle`: a settled order's executed price (`amount_out/amount_in`)
86 /// is worse than the order's limit price (`buy_amount/sell_amount`).
87 LimitPriceViolated = 24,
88 /// `BeginSettle`: an order's pull amounts sum to more than `u64::MAX`.
89 PullAmountOverflow = 25,
90 /// `BeginSettle`: filling this order would consume more tokens than the
91 /// maximum the user is willing to trade on this intent.
92 /// Sell: `amount_in > sell_amount`; buy: `amount_out > buy_amount`.
93 FillExceedsOrderAmount = 26,
94 /// `BeginSettle`: a non-`partially_fillable` order isn't filled exactly to
95 /// its amount (either under- or over-filled).
96 /// Sell: `amount_in != sell_amount`; buy: total `amount_out != buy_amount`.
97 OrderNotExactlyFilled = 27,
98 /// `BeginSettle`: the order's cumulative `amount_withdrawn` would exceed
99 /// `u64::MAX` once this settlement's pulls are added.
100 AmountWithdrawnOverflow = 28,
101 /// `BeginSettle`: the order's cumulative `amount_received` would exceed
102 /// `u64::MAX` once this settlement's push is added.
103 AmountReceivedOverflow = 29,
104 /// `ReclaimOrder` was called on an order that has not yet become eligible
105 /// for reclaim.
106 OrderNotReclaimable = 30,
107 /// `ReclaimOrder`'s `reclaim_recipient` account doesn't match the
108 /// `created_by` address recorded in the order.
109 ReclaimRecipientMismatch = 31,
110 /// `ReclaimBuffer`'s `reclaim_authority` account isn't a signer, or doesn't
111 /// match the `reclaim_authority` address recorded in the settlement state
112 /// PDA.
113 ReclaimAuthorityMismatch = 32,
114 /// A `ReclaimBuffer` `buffer_pda` doesn't sit at the canonical buffer PDA
115 /// derived from its paired `mint`.
116 ReclaimBufferNotCanonical = 33,
117 /// `TransferAuthority`'s signer is neither the manager nor the current
118 /// holder of the role being transferred, so it may not transfer it.
119 UnauthorizedAuthorityTransfer = 34,
120 /// `AddSolver`/`RemoveSolver`'s solver-authority account isn't a signer, or
121 /// doesn't match the `solver_authority` recorded in the settlement state
122 /// PDA, so it may not change the solver list.
123 UnauthorizedSolverManagement = 35,
124 /// `AddSolver`'s solver is already in the state PDA's solver list.
125 SolverAlreadyExists = 36,
126 /// `BeginSettle`'s solver account isn't a signer or isn't in the state PDA's
127 /// solver list, so it may not settle.
128 UnauthorizedSolver = 37,
129 /// `RemoveSolver`'s solver isn't in the state PDA's solver list.
130 SolverNotFound = 38,
131 /// `CreateBuffer` asked the token program how long a token account for a
132 /// mint has to be and couldn't read the answer, so it can't size the
133 /// buffer.
134 BufferSizeUnavailable = 39,
135 /// The token program for a given token or mint is not supported.
136 InvalidTokenProgram = 40,
137 /// `CreateSettlementOwnedOrder`'s settlement-owned-order-authority account
138 /// isn't a signer, or doesn't match the `settlement_owned_order_authority`
139 /// recorded in the settlement state PDA.
140 UnauthorizedSettlementOwnedOrder = 41,
141 /// An intent has a zero sell or buy amount, which is not supported.
142 ZeroOrderAmount = 42,
143 /// A mint account supplied to `BeginSettle` or `FinalizeSettle`
144 /// was not able to be parsed as such.
145 InvalidMint = 43,
146 /// `BeginSettle`: a paired `FinalizeSettle` push's destination is the very
147 /// buffer the push draws from, so settling it would move no funds yet still
148 /// record the declared amount as received.
149 PushSourceIsDestination = 44,
150 /// Moving lamports out of the native SOL buffer would empty it, which the
151 /// runtime would then delete.
152 NativeSolBufferEmptied = 45,
153 /// A buffer to be reclaimed holds more tokens than the burn limit supplied
154 /// for it, so its balance can't be cleared for closing.
155 ReclaimBufferBurnLimitExceeded = 46,
156 /// `WithdrawNativeSol`'s authority account isn't a signer, or doesn't
157 /// match the `settlement_owned_order_authority` recorded in the settlement
158 /// state PDA.
159 UnauthorizedNativeSolWithdrawal = 47,
160 /// `WithdrawNativeSol`'s native SOL buffer account isn't the canonical
161 /// native SOL buffer PDA.
162 NativeSolBufferMismatch = 48,
163}
164
165impl From<SettlementError> for u32 {
166 fn from(e: SettlementError) -> Self {
167 e as u32
168 }
169}
170
171impl From<SettlementError> for solana_program_error::ProgramError {
172 fn from(e: SettlementError) -> Self {
173 Self::Custom(e.into())
174 }
175}
176
177impl From<SettlementError> for solana_instruction_error::InstructionError {
178 fn from(e: SettlementError) -> Self {
179 Self::Custom(e.into())
180 }
181}
182
183/// Decodes the settlement error from an instruction that failed in the
184/// settlement program, handing back the original error if it isn't a known
185/// settlement error code.
186pub fn parse_settlement_error(
187 e: solana_instruction_error::InstructionError,
188) -> Result<SettlementError, solana_instruction_error::InstructionError> {
189 match e {
190 solana_instruction_error::InstructionError::Custom(code) => {
191 SettlementError::try_from(code).map_err(|_| e)
192 }
193 _ => Err(e),
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use solana_instruction_error::InstructionError;
200
201 use super::*;
202
203 #[test]
204 fn parse_settlement_error_decodes_custom_codes() {
205 assert_eq!(
206 parse_settlement_error(InstructionError::from(SettlementError::OrderNotReclaimable)),
207 Ok(SettlementError::OrderNotReclaimable)
208 );
209 assert_eq!(
210 parse_settlement_error(InstructionError::Custom(u32::MAX)),
211 Err(InstructionError::Custom(u32::MAX))
212 );
213 assert_eq!(
214 parse_settlement_error(InstructionError::InvalidAccountData),
215 Err(InstructionError::InvalidAccountData)
216 );
217 }
218}