diff --git a/Anchor.toml b/Anchor.toml
index 1c3949b7..c13048e0 100644
--- a/Anchor.toml
+++ b/Anchor.toml
@@ -1,4 +1,4 @@
-anchor_version = "0.20.1"
+anchor_version = "0.22.0"
 solana_version = "1.8.14"
 
 [workspace]
diff --git a/Cargo.lock b/Cargo.lock
index 0f4ecda7..d4c71977 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -39,9 +39,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-access-control"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "105c443a613f29212755fb6c5f946fa82dcf94a80528f643e0faa9d9faeb626b"
+checksum = "ed70c97998752288ce9840ae05dac6f7922856624d83bd8706941c363df5aa75"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -53,9 +53,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-account"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdae15851aa41972e9c18c987613c50a916c48c88c97ea3316156a5c772e5faa"
+checksum = "7325a9ddeab60ace310dd920b354a6318d31b4dd6d8172a518de3b8d58601035"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -68,9 +68,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-constant"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6356865217881d0bbea8aa70625937bec6d9952610f1ba2a2452a8e427000687"
+checksum = "1bfe53dec5dfe5742d949e7c21a3b813296c274183f4fbf669a070e45bd669c9"
 dependencies = [
  "anchor-syn",
  "proc-macro2",
@@ -79,9 +79,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-error"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebe998ce4e6e0cb0e291d1a1626bd30791cdfdd9d05523111bdf4fd053f08636"
+checksum = "5fda765864694d1ddeff66e8d97b015760379dc7136474633f7db0ec04577fc8"
 dependencies = [
  "anchor-syn",
  "proc-macro2",
@@ -91,9 +91,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-event"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5810498a20554c20354f5648b6041172f2035e58d09ad40dc051dc0d1501f80"
+checksum = "3ab29f55c9bf69f1e9a19838b5630204beaaddc4ca3ab8eed59a637e36b51428"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -104,9 +104,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-interface"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac83f085b2be8b3a3412989cf96cf7f683561db7d357c5aa4aa11d48bbb22213"
+checksum = "345ba1c992d29d3b666c4e5c8d8383d3291c4be3795dc13e218d59df55a08c21"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -118,9 +118,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-program"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73c56be575d89abcb192afa29deb87b2cdb3c39033abc02f2d16e6af999b23b7"
+checksum = "c2fd7fdf8c416d834650e7b8ef1db5746acc74c7333b3d9b3a385f5129e9b522"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -131,9 +131,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-attribute-state"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62ab002353b01fcb4f72cca256d5d62db39f9ff39b1d072280deee9798f1f524"
+checksum = "5426c71af1fcaa734d2f1dfde0f1e4ccc878be02707c767d6c9e88ef6686ecd5"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -144,9 +144,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-derive-accounts"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e653cdb322078d95221384c4a527a403560e509ac7cb2b53d3bd664b23c4d6"
+checksum = "2e597c70258147a5da1ca8801474e3a4a009214c1b7138cd863ef03eeba353a1"
 dependencies = [
  "anchor-syn",
  "anyhow",
@@ -157,9 +157,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-lang"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4815ad6334fd2f561f7ddcc3cfbeed87ed3003724171bd80ebe6383d5173ee8f"
+checksum = "f3fab2e8305bfe8971e04e963a442a767d81f8d61e73effdbe04df73bb7f9feb"
 dependencies = [
  "anchor-attribute-access-control",
  "anchor-attribute-account",
@@ -181,9 +181,9 @@ dependencies = [
 
 [[package]]
 name = "anchor-syn"
-version = "0.20.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be7bfb6991d79cce3495fb6ce0892f58a5c75a74c8d1c2fc6f62926066eb9f4"
+checksum = "68de711b6da0575993b85693d9e075a014de7e66ff4c29e0c38a54376b7d426d"
 dependencies = [
  "anyhow",
  "bs58 0.3.1",
diff --git a/flake.nix b/flake.nix
index 1b13f2ad..e1e00d15 100644
--- a/flake.nix
+++ b/flake.nix
@@ -20,7 +20,7 @@
           name = "ci";
           paths = with pkgs;
             (pkgs.lib.optionals pkgs.stdenv.isLinux ([ libudev ])) ++ [
-              anchor-0_20_1
+              anchor-0_22_0
               cargo-workspaces
               cargo-fuzz
 
diff --git a/stable-swap-anchor/Cargo.toml b/stable-swap-anchor/Cargo.toml
index f0bb49a3..5d4c1567 100644
--- a/stable-swap-anchor/Cargo.toml
+++ b/stable-swap-anchor/Cargo.toml
@@ -10,5 +10,5 @@ edition = "2021"
 keywords = ["solana", "saber", "anchor"]
 
 [dependencies]
-anchor-lang = ">=0.17"
+anchor-lang = ">=0.22.0"
 stable-swap-client = { path = "../stable-swap-client", version = "^1" }
diff --git a/stable-swap-anchor/src/instructions.rs b/stable-swap-anchor/src/instructions.rs
index e6acc1d9..5f427ff2 100644
--- a/stable-swap-anchor/src/instructions.rs
+++ b/stable-swap-anchor/src/instructions.rs
@@ -17,7 +17,7 @@ pub fn initialize<'a, 'b, 'c, 'info>(
     nonce: u8,
     amp_factor: u64,
     fees: stable_swap_client::fees::Fees,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::initialize(
         // token program ID is verified by the stable swap program
         ctx.accounts.token_program.key,
@@ -54,7 +54,8 @@ pub fn initialize<'a, 'b, 'c, 'info>(
             ctx.accounts.token_program,
         ],
         ctx.signer_seeds,
-    )
+    )?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::deposit] instruction.
@@ -71,7 +72,7 @@ pub fn deposit<'a, 'b, 'c, 'info>(
     token_a_amount: u64,
     token_b_amount: u64,
     min_mint_amount: u64,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::deposit(
         // token program ID is verified by the stable swap program
         ctx.accounts.user.token_program.key,
@@ -105,7 +106,8 @@ pub fn deposit<'a, 'b, 'c, 'info>(
             ctx.accounts.output_lp,
         ],
         ctx.signer_seeds,
-    )
+    )?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::swap] instruction.
@@ -120,7 +122,7 @@ pub fn swap<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, Swap<'info>>,
     amount_in: u64,
     minimum_amount_out: u64,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::swap(
         ctx.accounts.user.token_program.key,
         ctx.accounts.user.swap.key,
@@ -150,7 +152,8 @@ pub fn swap<'a, 'b, 'c, 'info>(
             ctx.accounts.output.fees,
         ],
         ctx.signer_seeds,
-    )
+    )?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::withdraw_one] instruction.
@@ -165,7 +168,7 @@ pub fn withdraw_one<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, WithdrawOne<'info>>,
     pool_token_amount: u64,
     minimum_token_amount: u64,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::withdraw_one(
         ctx.accounts.user.token_program.key,
         ctx.accounts.user.swap.key,
@@ -197,7 +200,8 @@ pub fn withdraw_one<'a, 'b, 'c, 'info>(
             ctx.accounts.output.fees,
         ],
         ctx.signer_seeds,
-    )
+    )?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::withdraw] instruction.
@@ -214,7 +218,7 @@ pub fn withdraw<'a, 'b, 'c, 'info>(
     pool_token_amount: u64,
     minimum_token_a_amount: u64,
     minimum_token_b_amount: u64,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::withdraw(
         // token program ID is verified by the stable swap program
         ctx.accounts.user.token_program.key,
@@ -234,7 +238,8 @@ pub fn withdraw<'a, 'b, 'c, 'info>(
         minimum_token_a_amount,
         minimum_token_b_amount,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::ramp_a] instruction.
@@ -249,53 +254,58 @@ pub fn ramp_a<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, AdminUserContext<'info>>,
     target_amp: u64,
     stop_ramp_ts: i64,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::ramp_a(
         ctx.accounts.swap.key,
         ctx.accounts.admin.key,
         target_amp,
         stop_ramp_ts,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::stop_ramp_a] instruction.
 pub fn stop_ramp_a<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, AdminUserContext<'info>>,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::stop_ramp_a(
         ctx.accounts.swap.key,
         ctx.accounts.admin.key,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::pause] instruction.
 pub fn pause<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, AdminUserContext<'info>>,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::pause(ctx.accounts.swap.key, ctx.accounts.admin.key)?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::unpause] instruction.
 pub fn unpause<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, AdminUserContext<'info>>,
-) -> ProgramResult {
+) -> Result<()> {
     let ix =
         stable_swap_client::instruction::unpause(ctx.accounts.swap.key, ctx.accounts.admin.key)?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::apply_new_admin] instruction.
 pub fn apply_new_admin<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, AdminUserContext<'info>>,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::apply_new_admin(
         ctx.accounts.swap.key,
         ctx.accounts.admin.key,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::commit_new_admin] instruction
@@ -305,26 +315,28 @@ pub fn apply_new_admin<'a, 'b, 'c, 'info>(
 /// * `new_admin` - Public key of the new admin.
 pub fn commit_new_admin<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, CommitNewAdmin<'info>>,
-) -> ProgramResult {
+) -> Result<()> {
     let admin_ctx = &ctx.accounts.admin_ctx;
     let ix = stable_swap_client::instruction::commit_new_admin(
         admin_ctx.swap.key,
         admin_ctx.admin.key,
         ctx.accounts.new_admin.key,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::set_fee_account] instruction.
 pub fn set_fee_account<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, SetFeeAccount<'info>>,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::set_fee_account(
         ctx.accounts.admin_ctx.swap.key,
         ctx.accounts.admin_ctx.admin.key,
         ctx.accounts.fee_account.to_account_info().key,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
 
 /// Creates and invokes a [stable_swap_client::instruction::set_new_fees] instruction.
@@ -335,11 +347,12 @@ pub fn set_fee_account<'a, 'b, 'c, 'info>(
 pub fn set_new_fees<'a, 'b, 'c, 'info>(
     ctx: CpiContext<'a, 'b, 'c, 'info, AdminUserContext<'info>>,
     fees: stable_swap_client::fees::Fees,
-) -> ProgramResult {
+) -> Result<()> {
     let ix = stable_swap_client::instruction::set_new_fees(
         ctx.accounts.swap.key,
         ctx.accounts.admin.key,
         fees,
     )?;
-    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)
+    solana_program::program::invoke_signed(&ix, &ctx.to_account_infos(), ctx.signer_seeds)?;
+    Ok(())
 }
diff --git a/stable-swap-anchor/src/lib.rs b/stable-swap-anchor/src/lib.rs
index ff740121..d95d5594 100644
--- a/stable-swap-anchor/src/lib.rs
+++ b/stable-swap-anchor/src/lib.rs
@@ -21,11 +21,11 @@ declare_id!("SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ");
 pub struct StableSwap;
 
 impl anchor_lang::AccountDeserialize for StableSwap {
-    fn try_deserialize(buf: &mut &[u8]) -> Result<Self, ProgramError> {
+    fn try_deserialize(buf: &mut &[u8]) -> Result<Self> {
         StableSwap::try_deserialize_unchecked(buf)
     }
 
-    fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result<Self, ProgramError> {
+    fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result<Self> {
         Ok(StableSwap)
     }
 }
diff --git a/stable-swap-anchor/src/state.rs b/stable-swap-anchor/src/state.rs
index b7ff0b00..f9aa0e2f 100644
--- a/stable-swap-anchor/src/state.rs
+++ b/stable-swap-anchor/src/state.rs
@@ -15,7 +15,7 @@ impl SwapInfo {
     pub const LEN: usize = stable_swap_client::state::SwapInfo::LEN;
 
     /// Computes the minimum rent exempt balance of a [SwapInfo].
-    pub fn minimum_rent_exempt_balance() -> Result<u64, ProgramError> {
+    pub fn minimum_rent_exempt_balance() -> Result<u64> {
         Ok(Rent::get()?.minimum_balance(Self::LEN))
     }
 }
@@ -35,18 +35,18 @@ impl Deref for SwapInfo {
 }
 
 impl anchor_lang::AccountSerialize for SwapInfo {
-    fn try_serialize<W: std::io::Write>(&self, _writer: &mut W) -> Result<(), ProgramError> {
+    fn try_serialize<W: std::io::Write>(&self, _writer: &mut W) -> Result<()> {
         // no-op
         Ok(())
     }
 }
 
 impl anchor_lang::AccountDeserialize for SwapInfo {
-    fn try_deserialize(buf: &mut &[u8]) -> Result<Self, ProgramError> {
+    fn try_deserialize(buf: &mut &[u8]) -> Result<Self> {
         SwapInfo::try_deserialize_unchecked(buf)
     }
 
-    fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError> {
-        stable_swap_client::state::SwapInfo::unpack(buf).map(SwapInfo)
+    fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self> {
+        Ok(stable_swap_client::state::SwapInfo::unpack(buf).map(SwapInfo)?)
     }
 }