Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit d4bd86e

Browse files
authored
Improve token error messages in token-swap (#3357)
* Move PrintProgramError impls * Add wrapper function * Add PrintProgramError to use declaration
1 parent 80f8890 commit d4bd86e

File tree

4 files changed

+254
-124
lines changed

4 files changed

+254
-124
lines changed

token-swap/program/src/error.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
//! Error types
22
33
use num_derive::FromPrimitive;
4-
use solana_program::{decode_error::DecodeError, program_error::ProgramError};
4+
use solana_program::{
5+
decode_error::DecodeError,
6+
msg,
7+
program_error::{PrintProgramError, ProgramError},
8+
};
59
use thiserror::Error;
610

711
/// Errors that may be returned by the TokenSwap program.
@@ -113,3 +117,75 @@ impl<T> DecodeError<T> for SwapError {
113117
"Swap Error"
114118
}
115119
}
120+
121+
impl PrintProgramError for SwapError {
122+
fn print<E>(&self)
123+
where
124+
E: 'static
125+
+ std::error::Error
126+
+ DecodeError<E>
127+
+ PrintProgramError
128+
+ num_traits::FromPrimitive,
129+
{
130+
match self {
131+
SwapError::AlreadyInUse => msg!("Error: Swap account already in use"),
132+
SwapError::InvalidProgramAddress => {
133+
msg!("Error: Invalid program address generated from bump seed and key")
134+
}
135+
SwapError::InvalidOwner => {
136+
msg!("Error: The input account owner is not the program address")
137+
}
138+
SwapError::InvalidOutputOwner => {
139+
msg!("Error: Output pool account owner cannot be the program address")
140+
}
141+
SwapError::ExpectedMint => msg!("Error: Deserialized account is not an SPL Token mint"),
142+
SwapError::ExpectedAccount => {
143+
msg!("Error: Deserialized account is not an SPL Token account")
144+
}
145+
SwapError::EmptySupply => msg!("Error: Input token account empty"),
146+
SwapError::InvalidSupply => msg!("Error: Pool token mint has a non-zero supply"),
147+
SwapError::RepeatedMint => msg!("Error: Swap input token accounts have the same mint"),
148+
SwapError::InvalidDelegate => msg!("Error: Token account has a delegate"),
149+
SwapError::InvalidInput => msg!("Error: InvalidInput"),
150+
SwapError::IncorrectSwapAccount => {
151+
msg!("Error: Address of the provided swap token account is incorrect")
152+
}
153+
SwapError::IncorrectPoolMint => {
154+
msg!("Error: Address of the provided pool token mint is incorrect")
155+
}
156+
SwapError::InvalidOutput => msg!("Error: InvalidOutput"),
157+
SwapError::CalculationFailure => msg!("Error: CalculationFailure"),
158+
SwapError::InvalidInstruction => msg!("Error: InvalidInstruction"),
159+
SwapError::ExceededSlippage => {
160+
msg!("Error: Swap instruction exceeds desired slippage limit")
161+
}
162+
SwapError::InvalidCloseAuthority => msg!("Error: Token account has a close authority"),
163+
SwapError::InvalidFreezeAuthority => {
164+
msg!("Error: Pool token mint has a freeze authority")
165+
}
166+
SwapError::IncorrectFeeAccount => msg!("Error: Pool fee token account incorrect"),
167+
SwapError::ZeroTradingTokens => {
168+
msg!("Error: Given pool token amount results in zero trading tokens")
169+
}
170+
SwapError::FeeCalculationFailure => msg!(
171+
"Error: The fee calculation failed due to overflow, underflow, or unexpected 0"
172+
),
173+
SwapError::ConversionFailure => msg!("Error: Conversion to or from u64 failed."),
174+
SwapError::InvalidFee => {
175+
msg!("Error: The provided fee does not match the program owner's constraints")
176+
}
177+
SwapError::IncorrectTokenProgramId => {
178+
msg!("Error: The provided token program does not match the token program expected by the swap")
179+
}
180+
SwapError::UnsupportedCurveType => {
181+
msg!("Error: The provided curve type is not supported by the program owner")
182+
}
183+
SwapError::InvalidCurve => {
184+
msg!("Error: The provided curve parameters are invalid")
185+
}
186+
SwapError::UnsupportedCurveOperation => {
187+
msg!("Error: The operation cannot be performed on the given curve")
188+
}
189+
}
190+
}
191+
}

token-swap/program/src/processor.rs

Lines changed: 119 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ use solana_program::{
1919
account_info::{next_account_info, AccountInfo},
2020
decode_error::DecodeError,
2121
entrypoint::ProgramResult,
22+
instruction::Instruction,
2223
msg,
2324
program::invoke_signed,
2425
program_error::{PrintProgramError, ProgramError},
2526
program_option::COption,
2627
program_pack::Pack,
2728
pubkey::Pubkey,
2829
};
29-
use std::convert::TryInto;
30+
use spl_token::error::TokenError;
31+
use std::{convert::TryInto, error::Error};
3032

3133
/// Program state handler.
3234
pub struct Processor {}
@@ -90,7 +92,7 @@ impl Processor {
9092
amount,
9193
)?;
9294

93-
invoke_signed(
95+
invoke_signed_wrapper::<TokenError>(
9496
&ix,
9597
&[burn_account, mint, authority, token_program],
9698
signers,
@@ -119,7 +121,11 @@ impl Processor {
119121
amount,
120122
)?;
121123

122-
invoke_signed(&ix, &[mint, destination, authority, token_program], signers)
124+
invoke_signed_wrapper::<TokenError>(
125+
&ix,
126+
&[mint, destination, authority, token_program],
127+
signers,
128+
)
123129
}
124130

125131
/// Issue a spl_token `Transfer` instruction.
@@ -143,7 +149,7 @@ impl Processor {
143149
&[],
144150
amount,
145151
)?;
146-
invoke_signed(
152+
invoke_signed_wrapper::<TokenError>(
147153
&ix,
148154
&[source, destination, authority, token_program],
149155
signers,
@@ -1069,74 +1075,6 @@ impl Processor {
10691075
}
10701076
}
10711077

1072-
impl PrintProgramError for SwapError {
1073-
fn print<E>(&self)
1074-
where
1075-
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
1076-
{
1077-
match self {
1078-
SwapError::AlreadyInUse => msg!("Error: Swap account already in use"),
1079-
SwapError::InvalidProgramAddress => {
1080-
msg!("Error: Invalid program address generated from bump seed and key")
1081-
}
1082-
SwapError::InvalidOwner => {
1083-
msg!("Error: The input account owner is not the program address")
1084-
}
1085-
SwapError::InvalidOutputOwner => {
1086-
msg!("Error: Output pool account owner cannot be the program address")
1087-
}
1088-
SwapError::ExpectedMint => msg!("Error: Deserialized account is not an SPL Token mint"),
1089-
SwapError::ExpectedAccount => {
1090-
msg!("Error: Deserialized account is not an SPL Token account")
1091-
}
1092-
SwapError::EmptySupply => msg!("Error: Input token account empty"),
1093-
SwapError::InvalidSupply => msg!("Error: Pool token mint has a non-zero supply"),
1094-
SwapError::RepeatedMint => msg!("Error: Swap input token accounts have the same mint"),
1095-
SwapError::InvalidDelegate => msg!("Error: Token account has a delegate"),
1096-
SwapError::InvalidInput => msg!("Error: InvalidInput"),
1097-
SwapError::IncorrectSwapAccount => {
1098-
msg!("Error: Address of the provided swap token account is incorrect")
1099-
}
1100-
SwapError::IncorrectPoolMint => {
1101-
msg!("Error: Address of the provided pool token mint is incorrect")
1102-
}
1103-
SwapError::InvalidOutput => msg!("Error: InvalidOutput"),
1104-
SwapError::CalculationFailure => msg!("Error: CalculationFailure"),
1105-
SwapError::InvalidInstruction => msg!("Error: InvalidInstruction"),
1106-
SwapError::ExceededSlippage => {
1107-
msg!("Error: Swap instruction exceeds desired slippage limit")
1108-
}
1109-
SwapError::InvalidCloseAuthority => msg!("Error: Token account has a close authority"),
1110-
SwapError::InvalidFreezeAuthority => {
1111-
msg!("Error: Pool token mint has a freeze authority")
1112-
}
1113-
SwapError::IncorrectFeeAccount => msg!("Error: Pool fee token account incorrect"),
1114-
SwapError::ZeroTradingTokens => {
1115-
msg!("Error: Given pool token amount results in zero trading tokens")
1116-
}
1117-
SwapError::FeeCalculationFailure => msg!(
1118-
"Error: The fee calculation failed due to overflow, underflow, or unexpected 0"
1119-
),
1120-
SwapError::ConversionFailure => msg!("Error: Conversion to or from u64 failed."),
1121-
SwapError::InvalidFee => {
1122-
msg!("Error: The provided fee does not match the program owner's constraints")
1123-
}
1124-
SwapError::IncorrectTokenProgramId => {
1125-
msg!("Error: The provided token program does not match the token program expected by the swap")
1126-
}
1127-
SwapError::UnsupportedCurveType => {
1128-
msg!("Error: The provided curve type is not supported by the program owner")
1129-
}
1130-
SwapError::InvalidCurve => {
1131-
msg!("Error: The provided curve parameters are invalid")
1132-
}
1133-
SwapError::UnsupportedCurveOperation => {
1134-
msg!("Error: The operation cannot be performed on the given curve")
1135-
}
1136-
}
1137-
}
1138-
}
1139-
11401078
fn to_u128(val: u64) -> Result<u128, SwapError> {
11411079
val.try_into().map_err(|_| SwapError::ConversionFailure)
11421080
}
@@ -1145,6 +1083,20 @@ fn to_u64(val: u128) -> Result<u64, SwapError> {
11451083
val.try_into().map_err(|_| SwapError::ConversionFailure)
11461084
}
11471085

1086+
fn invoke_signed_wrapper<T>(
1087+
instruction: &Instruction,
1088+
account_infos: &[AccountInfo],
1089+
signers_seeds: &[&[&[u8]]],
1090+
) -> Result<(), ProgramError>
1091+
where
1092+
T: 'static + PrintProgramError + DecodeError<T> + FromPrimitive + Error,
1093+
{
1094+
invoke_signed(instruction, account_infos, signers_seeds).map_err(|err| {
1095+
err.print::<T>();
1096+
err
1097+
})
1098+
}
1099+
11481100
#[cfg(test)]
11491101
mod tests {
11501102
use super::*;
@@ -1164,8 +1116,8 @@ mod tests {
11641116
use spl_token::{
11651117
error::TokenError,
11661118
instruction::{
1167-
approve, initialize_account, initialize_mint, mint_to, revoke, set_authority,
1168-
AuthorityType,
1119+
approve, freeze_account, initialize_account, initialize_mint, mint_to, revoke,
1120+
set_authority, AuthorityType,
11691121
},
11701122
};
11711123
use std::sync::Arc;
@@ -1947,6 +1899,99 @@ mod tests {
19471899
assert_eq!(err, ProgramError::InvalidAccountData);
19481900
}
19491901

1902+
#[test]
1903+
fn test_token_error() {
1904+
test_syscall_stubs();
1905+
let token_id = spl_token::id();
1906+
let swap_key = Pubkey::new_unique();
1907+
let mut mint = (
1908+
Pubkey::new_unique(),
1909+
Account::new(
1910+
mint_minimum_balance(),
1911+
spl_token::state::Mint::get_packed_len(),
1912+
&token_id,
1913+
),
1914+
);
1915+
let mut destination = (
1916+
Pubkey::new_unique(),
1917+
Account::new(
1918+
account_minimum_balance(),
1919+
spl_token::state::Account::get_packed_len(),
1920+
&token_id,
1921+
),
1922+
);
1923+
let mut token_program = (token_id, Account::default());
1924+
let (authority_key, bump_seed) =
1925+
Pubkey::find_program_address(&[&swap_key.to_bytes()[..]], &SWAP_PROGRAM_ID);
1926+
let mut authority = (authority_key, Account::default());
1927+
let swap_bytes = swap_key.to_bytes();
1928+
let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]];
1929+
let signers = &[&authority_signature_seeds[..]];
1930+
let mut rent_sysvar = (
1931+
Pubkey::new_unique(),
1932+
create_account_for_test(&Rent::default()),
1933+
);
1934+
do_process_instruction(
1935+
initialize_mint(
1936+
&token_program.0,
1937+
&mint.0,
1938+
&authority.0,
1939+
Some(&authority.0),
1940+
2,
1941+
)
1942+
.unwrap(),
1943+
vec![&mut mint.1, &mut rent_sysvar.1],
1944+
)
1945+
.unwrap();
1946+
do_process_instruction(
1947+
initialize_account(&token_program.0, &destination.0, &mint.0, &authority.0).unwrap(),
1948+
vec![
1949+
&mut destination.1,
1950+
&mut mint.1,
1951+
&mut authority.1,
1952+
&mut rent_sysvar.1,
1953+
&mut token_program.1,
1954+
],
1955+
)
1956+
.unwrap();
1957+
do_process_instruction(
1958+
freeze_account(&token_program.0, &destination.0, &mint.0, &authority.0, &[]).unwrap(),
1959+
vec![
1960+
&mut destination.1,
1961+
&mut mint.1,
1962+
&mut authority.1,
1963+
&mut token_program.1,
1964+
],
1965+
)
1966+
.unwrap();
1967+
let ix = mint_to(
1968+
&token_program.0,
1969+
&mint.0,
1970+
&destination.0,
1971+
&authority.0,
1972+
&[],
1973+
10,
1974+
)
1975+
.unwrap();
1976+
let mint_info = (&mut mint).into();
1977+
let destination_info = (&mut destination).into();
1978+
let authority_info = (&mut authority).into();
1979+
let token_program_info = (&mut token_program).into();
1980+
1981+
let err = invoke_signed_wrapper::<TokenError>(
1982+
&ix,
1983+
&[
1984+
mint_info,
1985+
destination_info,
1986+
authority_info,
1987+
token_program_info,
1988+
],
1989+
signers,
1990+
)
1991+
.unwrap_err();
1992+
assert_eq!(err, ProgramError::Custom(TokenError::AccountFrozen as u32));
1993+
}
1994+
19501995
#[test]
19511996
fn test_initialize() {
19521997
let user_key = Pubkey::new_unique();

0 commit comments

Comments
 (0)