If you notice some outdated information please let us know!
FAIL
The final review score is indicated as a percentage. The percentage is calculated as Achieved Points due to MAX Possible Points. For each element the answer can be either Yes/No or a percentage. For a detailed breakdown of the individual weights of each question, please consult this document.
Very simply, the audit looks for the following declarations from the developer's site. With these declarations, it is reasonable to trust the smart contracts.
This report is for informational purposes only and does not constitute investment advice of any kind, nor does it constitute an offer to provide investment advisory or other services. Nothing in this report shall be considered a solicitation or offer to buy or sell any security, token, future, option or other financial instrument or to offer or provide any investment advice or service to any person in any jurisdiction. Nothing contained in this report constitutes investment advice or offers any opinion with respect to the suitability of any security, and the views expressed in this report should not be taken as advice to buy, sell or hold any security. The information in this report should not be relied upon for the purpose of investing. In preparing the information contained in this report, we have not taken into account the investment needs, objectives and financial circumstances of any particular investor. This information has no regard to the specific investment objectives, financial situation and particular needs of any specific recipient of this information and investments discussed may not be suitable for all investors.
Any views expressed in this report by us were prepared based upon the information available to us at the time such views were written. The views expressed within this report are limited to DeFiSafety and the author and do not reflect those of any additional or third party and are strictly based upon DeFiSafety, its authors, interpretations and evaluation of relevant data. Changed or additional information could cause such views to change. All information is subject to possible correction. Information may quickly become unreliable for various reasons, including changes in market conditions or economic circumstances.
This completed report is copyright (c) DeFiSafety 2023. Permission is given to copy in whole, retaining this copyright label.
This section looks at the code deployed on the relevant chain that gets reviewed and its corresponding software repository. The document explaining these questions is here.
1. Are the smart contract addresses easy to find? (%)
Orca's whirlpool contracts are listed in their documentation.
2. How active is the primary contract? (%)
Contracts are used 100+ times a day, as indicated in the Appendix.
3. Does the protocol have a public software repository? (Y/N)
Location: https://github.com/orca-so
4. Is there a development history visible? (%)
Orca's whirlpool repository has 10 commits and 9 branches.
5. Is the team public (not anonymous)?
The team is public, and contributors cross reference their commitment to the protocol on personal social media.
The difference between this and the old link is solely the link. This section looks at the software documentation. The document explaining these questions is here.
6. Is there a whitepaper? (Y/N)
Location: https://docs.orca.so/
7. Is the protocol's software architecture documented? (Y/N)
This protocol's software architecture is documented.
8. Does the software documentation fully cover the deployed contracts' source code? (%)
Orca covers its whirlpool offering with some function documentation, though this is more of an instructional nature. More function-specific documentation would be of more utility.
9. Is it possible to trace the documented software to its implementation in the protocol's source code? (%)
There is some good software documentation, there is also good traceability. Users can easily trace the documentation to the code itself. Given that there is no documentation for the swap, we will award half marks here.
10. Has the protocol tested their deployed code? (%)
On their Whirlpool contract, Orca documents a test to code ratio of just 5%.
11. How covered is the protocol's code? (%)
There is evidence of limited testing in Orca's whirlpool repository.
12. Does the protocol provide scripts and instructions to run their tests? (Y/N)
Orca provides scripts and instructions to run their tests in their GitHub repository.
13. Is there a detailed report of the protocol's test results?(%)
There is no report of Orca's test results.
14. Has the protocol undergone Formal Verification? (Y/N)
Orca has not undergone a Formal Verification test.
15. Were the smart contracts deployed to a testnet? (Y/N)
Orca has not documented any deployments to a testnet. However, they do document test instructions on a local validator meaning we will award points for this.
This section looks at the 3rd party software audits done. It is explained in this document.
16. Is the protocol sufficiently audited? (%)
Orca's swap has been audit by a different firm (because it was forked). Orca's whirlpool contract has been audited twice, though only one report is public. As such, we will award points for one audit.
17. Is the bounty value acceptably high (%)
Orca does not offer a bug bounty.
This section covers the documentation of special access controls for a DeFi protocol. The admin access controls are the contracts that allow updating contracts or coefficients in the protocol. Since these contracts can allow the protocol admins to "change the rules", complete disclosure of capabilities is vital for user's transparency. It is explained in this document.
18. Is the protocol's admin control information easy to find?
Orca's Admin Control information is not documented.
19. Are relevant contracts clearly labelled as upgradeable or immutable? (%)
Orca's relevant contracts are not identified as immutable / upgradeable.
20. Is the type of smart contract ownership clearly indicated? (%)
Orca's smart contract ownership is not clearly indicated.
21. Are the protocol's smart contract change capabilities described? (%)
Orca's smart contract change capabilities are not identified in any contracts.
22. Is the protocol's admin control information easy to understand? (%)
No information relating to Orca's Admin Controls is documented.
23. Is there sufficient Pause Control documentation? (%)
Orca's pause control is not documented.
24. Is there sufficient Timelock documentation? (%)
Orca has no timelock documentation.
25. Is the Timelock of an adequate length? (Y/N)
Orca has no timelock documentation.
This section goes over the documentation that a protocol may or may not supply about their Oracle usage. Oracles are a fundamental part of DeFi as they are responsible for relaying tons of price data information to thousands of protocols using blockchain technology. Not only are they important for price feeds, but they are also an essential component of transaction verification and security. This is explained in this document.
26. Is the protocol's Oracle sufficiently documented? (%)
Orca's oracle source(s) are not documented.
27. Is front running mitigated by this protocol? (Y/N)
Orca documents no front running mitigation techniques.
28. Can flashloan attacks be applied to the protocol, and if so, are those flashloan attack risks mitigated? (Y/N)
Orca documents no flashloan countermeasures.
1//! State transition types
2
3use crate::curve::base::SwapCurve;
4use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
5use solana_program::{
6 program_error::ProgramError,
7 program_pack::{IsInitialized, Pack, Sealed},
8 pubkey::Pubkey,
9};
10
11/// Program states.
12#[repr(C)]
13#[derive(Debug, Default, PartialEq)]
14pub struct SwapInfo {
15 /// Initialized state.
16 pub is_initialized: bool,
17 /// Nonce used in program address.
18 /// The program address is created deterministically with the nonce,
19 /// swap program id, and swap account pubkey. This program address has
20 /// authority over the swap's token A account, token B account, and pool
21 /// token mint.
22 pub nonce: u8,
23
24 /// Program ID of the tokens being exchanged.
25 pub token_program_id: Pubkey,
26
27 /// Token A
28 pub token_a: Pubkey,
29 /// Token B
30 pub token_b: Pubkey,
31
32 /// Pool tokens are issued when A or B tokens are deposited.
33 /// Pool tokens can be withdrawn back to the original A or B token.
34 pub pool_mint: Pubkey,
35
36 /// Mint information for token A
37 pub token_a_mint: Pubkey,
38 /// Mint information for token B
39 pub token_b_mint: Pubkey,
40
41 /// Pool token account to receive trading and / or withdrawal fees
42 pub pool_fee_account: Pubkey,
43
44 /// Swap curve parameters, to be unpacked and used by the SwapCurve, which
45 /// calculates swaps, deposits, and withdrawals
46 pub swap_curve: SwapCurve,
47}
48
49impl Sealed for SwapInfo {}
50impl IsInitialized for SwapInfo {
51 fn is_initialized(&self) -> bool {
52 self.is_initialized
53 }
54}
55
56impl Pack for SwapInfo {
57 const LEN: usize = 291;
58
59 /// Unpacks a byte buffer into a [SwapInfo](struct.SwapInfo.html).
60 fn unpack_from_slice(input: &[u8]) -> Result<Self, ProgramError> {
61 let input = array_ref![input, 0, 291];
62 #[allow(clippy::ptr_offset_with_cast)]
63 let (
64 is_initialized,
65 nonce,
66 token_program_id,
67 token_a,
68 token_b,
69 pool_mint,
70 token_a_mint,
71 token_b_mint,
72 pool_fee_account,
73 swap_curve,
74 ) = array_refs![input, 1, 1, 32, 32, 32, 32, 32, 32, 32, 65];
75 Ok(Self {
76 is_initialized: match is_initialized {
77 [0] => false,
78 [1] => true,
79 _ => return Err(ProgramError::InvalidAccountData),
80 },
81 nonce: nonce[0],
82 token_program_id: Pubkey::new_from_array(*token_program_id),
83 token_a: Pubkey::new_from_array(*token_a),
84 token_b: Pubkey::new_from_array(*token_b),
85 pool_mint: Pubkey::new_from_array(*pool_mint),
86 token_a_mint: Pubkey::new_from_array(*token_a_mint),
87 token_b_mint: Pubkey::new_from_array(*token_b_mint),
88 pool_fee_account: Pubkey::new_from_array(*pool_fee_account),
89 swap_curve: SwapCurve::unpack_from_slice(swap_curve)?,
90 })
91 }
92
93 fn pack_into_slice(&self, output: &mut [u8]) {
94 let output = array_mut_ref![output, 0, 291];
95 let (
96 is_initialized,
97 nonce,
98 token_program_id,
99 token_a,
100 token_b,
101 pool_mint,
102 token_a_mint,
103 token_b_mint,
104 pool_fee_account,
105 swap_curve,
106 ) = mut_array_refs![output, 1, 1, 32, 32, 32, 32, 32, 32, 32, 65];
107 is_initialized[0] = self.is_initialized as u8;
108 nonce[0] = self.nonce;
109 token_program_id.copy_from_slice(self.token_program_id.as_ref());
110 token_a.copy_from_slice(self.token_a.as_ref());
111 token_b.copy_from_slice(self.token_b.as_ref());
112 pool_mint.copy_from_slice(self.pool_mint.as_ref());
113 token_a_mint.copy_from_slice(self.token_a_mint.as_ref());
114 token_b_mint.copy_from_slice(self.token_b_mint.as_ref());
115 pool_fee_account.copy_from_slice(self.pool_fee_account.as_ref());
116 self.swap_curve.pack_into_slice(&mut swap_curve[..]);
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::curve::flat::FlatCurve;
124
125 use std::convert::TryInto;
126
127 #[test]
128 fn test_swap_info_packing() {
129 let nonce = 255;
130 let curve_type_raw: u8 = 1;
131 let curve_type = curve_type_raw.try_into().unwrap();
132 let token_program_id_raw = [1u8; 32];
133 let token_a_raw = [1u8; 32];
134 let token_b_raw = [2u8; 32];
135 let pool_mint_raw = [3u8; 32];
136 let token_a_mint_raw = [4u8; 32];
137 let token_b_mint_raw = [5u8; 32];
138 let pool_fee_account_raw = [6u8; 32];
139 let token_program_id = Pubkey::new_from_array(token_program_id_raw);
140 let token_a = Pubkey::new_from_array(token_a_raw);
141 let token_b = Pubkey::new_from_array(token_b_raw);
142 let pool_mint = Pubkey::new_from_array(pool_mint_raw);
143 let token_a_mint = Pubkey::new_from_array(token_a_mint_raw);
144 let token_b_mint = Pubkey::new_from_array(token_b_mint_raw);
145 let pool_fee_account = Pubkey::new_from_array(pool_fee_account_raw);
146 let trade_fee_numerator = 1;
147 let trade_fee_denominator = 4;
148 let owner_trade_fee_numerator = 3;
149 let owner_trade_fee_denominator = 10;
150 let owner_withdraw_fee_numerator = 2;
151 let owner_withdraw_fee_denominator = 7;
152 let host_fee_numerator = 5;
153 let host_fee_denominator = 20;
154 let calculator = Box::new(FlatCurve {
155 trade_fee_numerator,
156 trade_fee_denominator,
157 owner_trade_fee_numerator,
158 owner_trade_fee_denominator,
159 owner_withdraw_fee_numerator,
160 owner_withdraw_fee_denominator,
161 host_fee_numerator,
162 host_fee_denominator,
163 });
164 let swap_curve = SwapCurve {
165 curve_type,
166 calculator,
167 };
168 let is_initialized = true;
169 let swap_info = SwapInfo {
170 is_initialized,
171 nonce,
172 token_program_id,
173 token_a,
174 token_b,
175 pool_mint,
176 token_a_mint,
177 token_b_mint,
178 pool_fee_account,
179 swap_curve,
180 };
181
182 let mut packed = [0u8; SwapInfo::LEN];
183 SwapInfo::pack_into_slice(&swap_info, &mut packed);
184 let unpacked = SwapInfo::unpack(&packed).unwrap();
185 assert_eq!(swap_info, unpacked);
186
187 let mut packed = vec![];
188 packed.push(1u8);
189 packed.push(nonce);
190 packed.extend_from_slice(&token_program_id_raw);
191 packed.extend_from_slice(&token_a_raw);
192 packed.extend_from_slice(&token_b_raw);
193 packed.extend_from_slice(&pool_mint_raw);
194 packed.extend_from_slice(&token_a_mint_raw);
195 packed.extend_from_slice(&token_b_mint_raw);
196 packed.extend_from_slice(&pool_fee_account_raw);
197 packed.push(curve_type_raw);
198 packed.extend_from_slice(&trade_fee_numerator.to_le_bytes());
199 packed.extend_from_slice(&trade_fee_denominator.to_le_bytes());
200 packed.extend_from_slice(&owner_trade_fee_numerator.to_le_bytes());
201 packed.extend_from_slice(&owner_trade_fee_denominator.to_le_bytes());
202 packed.extend_from_slice(&owner_withdraw_fee_numerator.to_le_bytes());
203 packed.extend_from_slice(&owner_withdraw_fee_denominator.to_le_bytes());
204 packed.extend_from_slice(&host_fee_numerator.to_le_bytes());
205 packed.extend_from_slice(&host_fee_denominator.to_le_bytes());
206 let unpacked = SwapInfo::unpack(&packed).unwrap();
207 assert_eq!(swap_info, unpacked);
208
209 let packed = [0u8; SwapInfo::LEN];
210 let swap_info: SwapInfo = Default::default();
211 let unpack_unchecked = SwapInfo::unpack_unchecked(&packed).unwrap();
212 assert_eq!(unpack_unchecked, swap_info);
213 let err = SwapInfo::unpack(&packed).unwrap_err();
214 assert_eq!(err, ProgramError::UninitializedAccount);
215 }
216}
Tests to Code: 206 / 4422 = 5 %