Skip to content

Commit 758fd76

Browse files
committed
refactor: split into protocol-zap and zap-sdk
1 parent fb4f24d commit 758fd76

File tree

19 files changed

+207
-185
lines changed

19 files changed

+207
-185
lines changed

Cargo.lock

Lines changed: 15 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["programs/*", "libs/*", "zap-sdk"]
2+
members = ["programs/*", "libs/*", "zap-sdk", "protocol-zap"]
33
resolver = "2"
44

55
[profile.release]

programs/zap/src/constants.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ use zap_sdk::constants::{
88

99
#[constant]
1010
pub const WHITELISTED_AMM_PROGRAMS: [(Pubkey, [u8; 8]); 4] = [
11-
(Pubkey::new_from_array(DAMM_V2), DAMM_V2_SWAP_DISC),
12-
(Pubkey::new_from_array(DLMM), DLMM_SWAP2_DISC),
13-
(Pubkey::new_from_array(JUP_V6), JUP_V6_ROUTE_DISC),
14-
(
15-
Pubkey::new_from_array(JUP_V6),
16-
JUP_V6_SHARED_ACCOUNT_ROUTE_DISC,
17-
),
11+
(DAMM_V2, DAMM_V2_SWAP_DISC),
12+
(DLMM, DLMM_SWAP2_DISC),
13+
(JUP_V6, JUP_V6_ROUTE_DISC),
14+
(JUP_V6, JUP_V6_SHARED_ACCOUNT_ROUTE_DISC),
1815
];
1916

2017
#[constant]

protocol-zap/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "protocol-zap"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
borsh = "0.10"
8+
jupiter = { path = "../libs/jupiter" }
9+
ruint = { workspace = true }
10+
num_enum = "0.7"
11+
pinocchio = "0.9"
12+
pinocchio-pubkey = "0.3"
13+
thiserror = "2"
14+
zap-sdk = { path = "../zap-sdk" }

protocol-zap/src/constants.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use pinocchio::pubkey::Pubkey;
2+
use pinocchio_pubkey::pubkey;
3+
4+
pub const JUP_V6_SHARED_ACCOUNT_ROUTE_AMOUNT_IN_REVERSE_OFFSET: usize = 1 + 2 + 8 + 8; // Due to jupiter parameters have dynamic length type (vec), we have to do parameters_data.length - JUP_V6_SHARED_ACCOUNT_ROUTE_AMOUNT_IN_REVERSE_OFFSET
5+
pub const JUP_V6_SHARED_ACCOUNT_ROUTE_SOURCE_ACCOUNT_INDEX: usize = 3;
6+
pub const JUP_V6_SHARED_ACCOUNT_ROUTE_DESTINATION_ACCOUNT_INDEX: usize = 6;
7+
8+
pub const JUP_V6_ROUTE_AMOUNT_IN_REVERSE_OFFSET: usize = 1 + 2 + 8 + 8;
9+
pub const JUP_V6_ROUTE_SOURCE_ACCOUNT_INDEX: usize = 2;
10+
pub const JUP_V6_ROUTE_DESTINATION_ACCOUNT_INDEX: usize = 4;
11+
12+
pub const DLMM_SWAP2_AMOUNT_IN_OFFSET: u16 = 8;
13+
pub const DLMM_SWAP2_SOURCE_ACCOUNT_INDEX: usize = 4;
14+
pub const DLMM_SWAP2_DESTINATION_ACCOUNT_INDEX: usize = 5;
15+
16+
pub const DAMM_V2_SWAP_AMOUNT_IN_OFFSET: u16 = 8;
17+
pub const DAMM_V2_SWAP_SOURCE_ACCOUNT_INDEX: usize = 2;
18+
pub const DAMM_V2_SWAP_DESTINATION_ACCOUNT_INDEX: usize = 3;
19+
20+
pub const ZAP: Pubkey = pubkey!("zapvX9M3uf5pvy4wRPAbQgdQsM1xmuiFnkfHKPvwMiz");
21+
pub const ZAP_OUT_DISC: [u8; 8] = [155, 108, 185, 112, 104, 210, 161, 64];
22+
23+
pub const USDC_ADDRESS: Pubkey = pubkey!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
24+
25+
pub const SOL_ADDRESS: Pubkey = pubkey!("So11111111111111111111111111111111111111112");
26+
27+
pub const MINTS_DISALLOWED_TO_ZAP_OUT: [Pubkey; 2] = [USDC_ADDRESS, SOL_ADDRESS];
28+
29+
pub const SPL_TOKEN_PROGRAM_ID: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
30+
31+
pub const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: Pubkey =
32+
pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ use crate::{
33
DAMM_V2_SWAP_AMOUNT_IN_OFFSET, DAMM_V2_SWAP_DESTINATION_ACCOUNT_INDEX,
44
DAMM_V2_SWAP_SOURCE_ACCOUNT_INDEX,
55
},
6-
error::ZapSdkError,
6+
error::ProtozolZapError,
77
RawZapOutAmmInfo, ZapInfoProcessor, ZapOutParameters,
88
};
99

1010
pub struct ZapDammV2InfoProcessor;
1111

1212
impl ZapInfoProcessor for ZapDammV2InfoProcessor {
13-
fn validate_payload(&self, _payload: &[u8]) -> Result<(), ZapSdkError> {
13+
fn validate_payload(&self, _payload: &[u8]) -> Result<(), ProtozolZapError> {
1414
Ok(())
1515
}
1616

1717
fn extract_raw_zap_out_amm_info(
1818
&self,
1919
_zap_params: &ZapOutParameters,
20-
) -> Result<RawZapOutAmmInfo, ZapSdkError> {
20+
) -> Result<RawZapOutAmmInfo, ProtozolZapError> {
2121
Ok(RawZapOutAmmInfo {
2222
source_index: DAMM_V2_SWAP_SOURCE_ACCOUNT_INDEX,
2323
destination_index: DAMM_V2_SWAP_DESTINATION_ACCOUNT_INDEX,
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ use crate::{
33
DLMM_SWAP2_AMOUNT_IN_OFFSET, DLMM_SWAP2_DESTINATION_ACCOUNT_INDEX,
44
DLMM_SWAP2_SOURCE_ACCOUNT_INDEX,
55
},
6-
error::ZapSdkError,
6+
error::ProtozolZapError,
77
RawZapOutAmmInfo, ZapInfoProcessor, ZapOutParameters,
88
};
99

1010
pub struct ZapDlmmInfoProcessor;
1111

1212
impl ZapInfoProcessor for ZapDlmmInfoProcessor {
13-
fn validate_payload(&self, _payload: &[u8]) -> Result<(), ZapSdkError> {
13+
fn validate_payload(&self, _payload: &[u8]) -> Result<(), ProtozolZapError> {
1414
Ok(())
1515
}
1616

1717
fn extract_raw_zap_out_amm_info(
1818
&self,
1919
_zap_params: &ZapOutParameters,
20-
) -> Result<RawZapOutAmmInfo, ZapSdkError> {
20+
) -> Result<RawZapOutAmmInfo, ProtozolZapError> {
2121
Ok(RawZapOutAmmInfo {
2222
source_index: DLMM_SWAP2_SOURCE_ACCOUNT_INDEX,
2323
destination_index: DLMM_SWAP2_DESTINATION_ACCOUNT_INDEX,
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use thiserror::Error;
44

55
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
66
#[repr(u32)]
7-
pub enum ZapSdkError {
7+
pub enum ProtozolZapError {
88
#[error("Math operation overflow")]
99
MathOverflow = 0,
1010

@@ -30,8 +30,8 @@ pub enum ZapSdkError {
3030
InvalidZapAccounts = 7,
3131
}
3232

33-
impl From<ZapSdkError> for ProgramError {
34-
fn from(e: ZapSdkError) -> Self {
33+
impl From<ProtozolZapError> for ProgramError {
34+
fn from(e: ProtozolZapError) -> Self {
3535
ProgramError::Custom(e as u32)
3636
}
3737
}
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
JUP_V6_SHARED_ACCOUNT_ROUTE_DESTINATION_ACCOUNT_INDEX,
66
JUP_V6_SHARED_ACCOUNT_ROUTE_SOURCE_ACCOUNT_INDEX,
77
},
8-
error::ZapSdkError,
8+
error::ProtozolZapError,
99
safe_math::{SafeCast, SafeMath},
1010
RawZapOutAmmInfo, ZapInfoProcessor, ZapOutParameters,
1111
};
@@ -15,7 +15,7 @@ use jupiter::types::Swap;
1515

1616
pub struct ZapJupV6RouteInfoProcessor;
1717

18-
fn ensure_whitelisted_swap_leg(route_plan_steps: &[RoutePlanStep]) -> Result<(), ZapSdkError> {
18+
fn ensure_whitelisted_swap_leg(route_plan_steps: &[RoutePlanStep]) -> Result<(), ProtozolZapError> {
1919
for step in route_plan_steps {
2020
match step.swap {
2121
Swap::Meteora
@@ -33,7 +33,7 @@ fn ensure_whitelisted_swap_leg(route_plan_steps: &[RoutePlanStep]) -> Result<(),
3333
| Swap::RaydiumClmmV2 => {
3434
// whitelisted swap leg
3535
}
36-
_ => return Err(ZapSdkError::InvalidZapOutParameters),
36+
_ => return Err(ProtozolZapError::InvalidZapOutParameters),
3737
}
3838
}
3939

@@ -45,7 +45,7 @@ fn ensure_whitelisted_swap_leg(route_plan_steps: &[RoutePlanStep]) -> Result<(),
4545
/// - All swap paths must converge to exactly one terminal output
4646
pub(crate) fn ensure_route_plan_fully_converges(
4747
route_plan_steps: &[RoutePlanStep],
48-
) -> Result<(), ZapSdkError> {
48+
) -> Result<(), ProtozolZapError> {
4949
// Verify each unique input_index sums to exactly 100%
5050
for (i, step) in route_plan_steps.iter().enumerate() {
5151
// Only process first occurrence of each input_index
@@ -60,10 +60,10 @@ pub(crate) fn ensure_route_plan_fully_converges(
6060
.iter()
6161
.filter(|s| s.input_index == step.input_index)
6262
.try_fold(0u8, |acc, s| acc.checked_add(s.percent))
63-
.ok_or(ZapSdkError::MathOverflow)?;
63+
.ok_or(ProtozolZapError::MathOverflow)?;
6464

6565
if percent_sum != 100 {
66-
return Err(ZapSdkError::InvalidZapOutParameters);
66+
return Err(ProtozolZapError::InvalidZapOutParameters);
6767
}
6868
}
6969

@@ -83,22 +83,22 @@ pub(crate) fn ensure_route_plan_fully_converges(
8383
.count();
8484

8585
if terminal_count != 1 {
86-
return Err(ZapSdkError::InvalidZapOutParameters);
86+
return Err(ProtozolZapError::InvalidZapOutParameters);
8787
}
8888

8989
Ok(())
9090
}
9191

9292
impl ZapInfoProcessor for ZapJupV6RouteInfoProcessor {
93-
fn validate_payload(&self, payload: &[u8]) -> Result<(), ZapSdkError> {
93+
fn validate_payload(&self, payload: &[u8]) -> Result<(), ProtozolZapError> {
9494
let route_params = jupiter::client::args::Route::try_from_slice(payload)
95-
.map_err(|_| ZapSdkError::InvalidZapOutParameters)?;
95+
.map_err(|_| ProtozolZapError::InvalidZapOutParameters)?;
9696
ensure_whitelisted_swap_leg(&route_params.route_plan)?;
9797
ensure_route_plan_fully_converges(&route_params.route_plan)?;
9898

9999
// Ensure no platform_fee_bps is 0, so operator can't steal funds by providing their account as platform_fee_account
100100
if route_params.platform_fee_bps != 0 {
101-
return Err(ZapSdkError::InvalidZapOutParameters);
101+
return Err(ProtozolZapError::InvalidZapOutParameters);
102102
}
103103

104104
Ok(())
@@ -107,7 +107,7 @@ impl ZapInfoProcessor for ZapJupV6RouteInfoProcessor {
107107
fn extract_raw_zap_out_amm_info(
108108
&self,
109109
zap_params: &ZapOutParameters,
110-
) -> Result<RawZapOutAmmInfo, ZapSdkError> {
110+
) -> Result<RawZapOutAmmInfo, ProtozolZapError> {
111111
let amount_in_offset = zap_params
112112
.payload_data
113113
.len()
@@ -125,15 +125,15 @@ impl ZapInfoProcessor for ZapJupV6RouteInfoProcessor {
125125
pub struct ZapJupV6SharedRouteInfoProcessor;
126126

127127
impl ZapInfoProcessor for ZapJupV6SharedRouteInfoProcessor {
128-
fn validate_payload(&self, payload: &[u8]) -> Result<(), ZapSdkError> {
128+
fn validate_payload(&self, payload: &[u8]) -> Result<(), ProtozolZapError> {
129129
let route_params = jupiter::client::args::SharedAccountsRoute::try_from_slice(payload)
130-
.map_err(|_| ZapSdkError::InvalidZapOutParameters)?;
130+
.map_err(|_| ProtozolZapError::InvalidZapOutParameters)?;
131131
ensure_whitelisted_swap_leg(&route_params.route_plan)?;
132132
ensure_route_plan_fully_converges(&route_params.route_plan)?;
133133

134134
// Ensure no platform_fee_bps is 0, so operator can't steal funds by providing their account as platform_fee_account
135135
if route_params.platform_fee_bps != 0 {
136-
return Err(ZapSdkError::InvalidZapOutParameters);
136+
return Err(ProtozolZapError::InvalidZapOutParameters);
137137
}
138138

139139
Ok(())
@@ -142,7 +142,7 @@ impl ZapInfoProcessor for ZapJupV6SharedRouteInfoProcessor {
142142
fn extract_raw_zap_out_amm_info(
143143
&self,
144144
zap_params: &ZapOutParameters,
145-
) -> Result<RawZapOutAmmInfo, ZapSdkError> {
145+
) -> Result<RawZapOutAmmInfo, ProtozolZapError> {
146146
let amount_in_offset = zap_params
147147
.payload_data
148148
.len()

protocol-zap/src/lib.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use borsh::{BorshDeserialize, BorshSerialize};
2+
use pinocchio::pubkey::Pubkey;
3+
pub mod constants;
4+
pub mod damm_v2_zap;
5+
use damm_v2_zap::*;
6+
pub mod dlmm_zap;
7+
use dlmm_zap::ZapDlmmInfoProcessor;
8+
use zap_sdk::constants::{
9+
DAMM_V2, DAMM_V2_SWAP_DISC, DLMM, DLMM_SWAP2_DISC, JUP_V6, JUP_V6_ROUTE_DISC,
10+
JUP_V6_SHARED_ACCOUNT_ROUTE_DISC,
11+
};
12+
13+
use crate::{
14+
error::ProtozolZapError,
15+
jup_v6_zap::{ZapJupV6RouteInfoProcessor, ZapJupV6SharedRouteInfoProcessor},
16+
};
17+
pub mod error;
18+
pub mod jup_v6_zap;
19+
pub mod safe_math;
20+
pub mod tests;
21+
pub mod utils;
22+
23+
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
24+
pub struct ZapOutParameters {
25+
pub percentage: u8,
26+
pub offset_amount_in: u16,
27+
pub pre_user_token_balance: u64,
28+
pub max_swap_amount: u64, // avoid the issue someone send token to user token account when user zap out
29+
pub payload_data: Vec<u8>,
30+
}
31+
32+
pub struct RawZapOutAmmInfo {
33+
source_index: usize,
34+
destination_index: usize,
35+
amount_in_offset: u16,
36+
}
37+
38+
pub trait ZapInfoProcessor {
39+
fn validate_payload(&self, payload: &[u8]) -> Result<(), ProtozolZapError>;
40+
fn extract_raw_zap_out_amm_info(
41+
&self,
42+
zap_params: &ZapOutParameters,
43+
) -> Result<RawZapOutAmmInfo, ProtozolZapError>;
44+
}
45+
46+
const DAMM_V2_SWAP_DISC_REF: &[u8] = &DAMM_V2_SWAP_DISC;
47+
const DLMM_SWAP2_DISC_REF: &[u8] = &DLMM_SWAP2_DISC;
48+
const JUP_V6_ROUTE_DISC_REF: &[u8] = &JUP_V6_ROUTE_DISC;
49+
const JUP_V6_SHARED_ACCOUNT_ROUTE_DISC_REF: &[u8] = &JUP_V6_SHARED_ACCOUNT_ROUTE_DISC;
50+
51+
const DLMM_ADDRESS: [u8; 32] = DLMM.to_bytes();
52+
const DAMM_V2_ADDRESS: [u8; 32] = DAMM_V2.to_bytes();
53+
const JUP_V6_ADDRESS: [u8; 32] = JUP_V6.to_bytes();
54+
55+
pub fn get_zap_amm_processor(
56+
amm_disc: &[u8],
57+
amm_program_address: Pubkey,
58+
) -> Result<Box<dyn ZapInfoProcessor>, ProtozolZapError> {
59+
match (amm_disc, amm_program_address) {
60+
(DLMM_SWAP2_DISC_REF, DLMM_ADDRESS) => Ok(Box::new(ZapDlmmInfoProcessor)),
61+
(DAMM_V2_SWAP_DISC_REF, DAMM_V2_ADDRESS) => Ok(Box::new(ZapDammV2InfoProcessor)),
62+
(JUP_V6_ROUTE_DISC_REF, JUP_V6_ADDRESS) => Ok(Box::new(ZapJupV6RouteInfoProcessor)),
63+
(JUP_V6_SHARED_ACCOUNT_ROUTE_DISC_REF, JUP_V6_ADDRESS) => {
64+
Ok(Box::new(ZapJupV6SharedRouteInfoProcessor))
65+
}
66+
_ => Err(ProtozolZapError::InvalidZapOutParameters),
67+
}
68+
}

0 commit comments

Comments
 (0)