If you notice some outdated information please let us know!
PASS
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? (%)
They can be found at https://guide.ref.finance/developers/contracts, as indicated in the Appendix.
2. How active is the primary contract? (%)
Contract v2.ref-finance.near is used hundreds of times a day, as indicated in the Appendix.
3. Does the protocol have a public software repository? (Y/N)
Location: https://github.com/ref-finance
4. Is there a development history visible? (%)
At 64 commits but 41 branches, there is a good reference of development history documented.
5. Is the team public (not anonymous)?
Ref has multiple public and anonymous developers working on it. These are conveniently listed in one place for verification.
This section looks at the software documentation. The document explaining these questions is here.
6. Is there a whitepaper? (Y/N)
Location: https://guide.ref.finance/
7. Is the protocol's software architecture documented? (Y/N)
This protocol's software architecture is documented in this location. This is good architecture documentation.
8. Does the software documentation fully cover the deployed contracts' source code? (%)
There is good coverage of critical deployed contracts by software function documentation. The exchange and farming contracts are covered by good software function documentation. In addition, other contracts such as DAO / Vesting contracts are covered by their software function documentation.
9. Is it possible to trace the documented software to its implementation in the protocol's source code? (%)
There is perfect traceability between software documentation and implemented code. Users can immediately see the location of the public code in Ref's github repository which is conveniently linked.
10. Has the protocol tested their deployed code? (%)
Code examples are in the Appendix at the end of this report.. As per the SLOC, there is 86% testing to code (TtC). This score is guided by the Test to Code ratio (TtC). Generally a good test to code ratio is over 100%. However, the reviewer's best judgement is the final deciding factor.
11. How covered is the protocol's code? (%)
Ref's code coverage stands at 51%, as identifed in their Jita audit.
12. Does the protocol provide scripts and instructions to run their tests? (Y/N)
Scripts/Instructions location: https://github.com/ref-finance/ref-contracts#testing
13. Is there a detailed report of the protocol's test results?(%)
There is no test report documented by Ref.
14. Has the protocol undergone Formal Verification? (Y/N)
Ref has not undergone formal verification.
15. Were the smart contracts deployed to a testnet? (Y/N)
Ref has documented a deployment to a testnet.
This section looks at the 3rd party software audits done. It is explained in this document.
16. Is the protocol sufficiently audited? (%)
Ref has been audited twice by Jita post-launch, firstly and secondly. Additionally, BlockSec had audited Ref's V2 and veTokenomic contracts pre-launch.
17. Is the bounty value acceptably high (%)
Ref has a $250K active bug bounty. Not only does this cover their smart contracts but also their front-end, which we consider to be often as important and largely overlooked. They should be commended for this.
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?
Admin control information is easily found in Ref's contract documentation. An easy to understand table is documented.
19. Are relevant contracts clearly labelled as upgradeable or immutable? (%)
Each upgradeable contract is identified by Ref's contract documentation. The specificity of this documentation indicates good process.
20. Is the type of smart contract ownership clearly indicated? (%)
Ref contract ownership is clearly indicated in their contract documentation. Indeed, significant work has been put into identifying exact contract ownership in exact locations. This is commendable.
21. Are the protocol's smart contract change capabilities described? (%)
Smart contract change capabilities are identified in each of Ref's contracts in their contract documentation.
22. Is the protocol's admin control information easy to understand? (%)
This information is in easy to understand language.
23. Is there sufficient Pause Control documentation? (%)
Ref uses Guardians that function as their pause control. There is good and specific documentation relating to the processes in which the pause control is activated.
24. Is there sufficient Timelock documentation? (%)
Ref does not use a timelock and this is explained in their contract documentation. However, since some contracts are subject to DAO governance timeframes, some contracts are subject to a 24-48h delay in between proposal and going into effect.
25. Is the Timelock of an adequate length? (Y/N)
Ref does not use a formal timelock, and this is explained in their contract 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. These questions are explained in this document.
26. Is the protocol's Oracle sufficiently documented? (%)
Ref does not use an oracle, and this is stated in their GitBook. Instead, prices are dependent on pool conditions.
27. Is front running mitigated by this protocol? (Y/N)
This protocol 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)
This protocol documents no flashloan attack countermeasures. Nevertheless, since flashloans are not currently a documented possibility on NEAR, this protocol does not need to do so.
1use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
2use near_sdk::{AccountId, Balance};
3
4use crate::admin_fee::AdminFees;
5use crate::simple_pool::SimplePool;
6use crate::stable_swap::StableSwapPool;
7use crate::utils::SwapVolume;
8
9/// Generic Pool, providing wrapper around different implementations of swap pools.
10/// Allows to add new types of pools just by adding extra item in the enum without needing to migrate the storage.
11#[derive(BorshSerialize, BorshDeserialize)]
12pub enum Pool {
13 SimplePool(SimplePool),
14 StableSwapPool(StableSwapPool),
15}
16
17impl Pool {
18 /// Returns pool kind.
19 pub fn kind(&self) -> String {
20 match self {
21 Pool::SimplePool(_) => "SIMPLE_POOL".to_string(),
22 Pool::StableSwapPool(_) => "STABLE_SWAP".to_string(),
23 }
24 }
25
26 /// Returns which tokens are in the underlying pool.
27 pub fn tokens(&self) -> &[AccountId] {
28 match self {
29 Pool::SimplePool(pool) => pool.tokens(),
30 Pool::StableSwapPool(pool) => pool.tokens(),
31 }
32 }
33
34 /// Adds liquidity into underlying pool.
35 /// Updates amounts to amount kept in the pool.
36 pub fn add_liquidity(
37 &mut self,
38 sender_id: &AccountId,
39 amounts: &mut Vec<Balance>,
40 ) -> Balance {
41 match self {
42 Pool::SimplePool(pool) => pool.add_liquidity(sender_id, amounts),
43 Pool::StableSwapPool(_) => unimplemented!(),
44 }
45 }
46
47 pub fn add_stable_liquidity(
48 &mut self,
49 sender_id: &AccountId,
50 amounts: &Vec<Balance>,
51 min_shares: Balance,
52 admin_fee: AdminFees,
53 ) -> Balance {
54 match self {
55 Pool::SimplePool(_) => unimplemented!(),
56 Pool::StableSwapPool(pool) => pool.add_liquidity(sender_id, amounts, min_shares, &admin_fee),
57 }
58 }
59
60 /// Removes liquidity from underlying pool.
61 pub fn remove_liquidity(
62 &mut self,
63 sender_id: &AccountId,
64 shares: Balance,
65 min_amounts: Vec<Balance>,
66 ) -> Vec<Balance> {
67 match self {
68 Pool::SimplePool(pool) => pool.remove_liquidity(sender_id, shares, min_amounts),
69 Pool::StableSwapPool(pool) => {
70 pool.remove_liquidity_by_shares(sender_id, shares, min_amounts)
71 }
72 }
73 }
74
75 /// Removes liquidity from underlying pool.
76 pub fn remove_liquidity_by_tokens(
77 &mut self,
78 sender_id: &AccountId,
79 amounts: Vec<Balance>,
80 max_burn_shares: Balance,
81 admin_fee: AdminFees,
82 ) -> Balance {
83 match self {
84 Pool::SimplePool(_) => unimplemented!(),
85 Pool::StableSwapPool(pool) => {
86 pool.remove_liquidity_by_tokens(sender_id, amounts, max_burn_shares, &admin_fee)
87 }
88 }
89 }
90
91 /// Returns how many tokens will one receive swapping given amount of token_in for token_out.
92 pub fn get_return(
93 &self,
94 token_in: &AccountId,
95 amount_in: Balance,
96 token_out: &AccountId,
97 fees: &AdminFees,
98 ) -> Balance {
99 match self {
100 Pool::SimplePool(pool) => pool.get_return(token_in, amount_in, token_out),
101 Pool::StableSwapPool(pool) => pool.get_return(token_in, amount_in, token_out, fees),
102 }
103 }
104
105 /// Return share decimal.
106 pub fn get_share_decimal(&self) -> u8 {
107 match self {
108 Pool::SimplePool(_) => 24,
109 Pool::StableSwapPool(_) => 18,
110 }
111 }
112
113 /// Returns given pool's total fee.
114 pub fn get_fee(&self) -> u32 {
115 match self {
116 Pool::SimplePool(pool) => pool.get_fee(),
117 Pool::StableSwapPool(pool) => pool.get_fee(),
118 }
119 }
120
121 /// Returns volumes of the given pool.
122 pub fn get_volumes(&self) -> Vec<SwapVolume> {
123 match self {
124 Pool::SimplePool(pool) => pool.get_volumes(),
125 Pool::StableSwapPool(pool) => pool.get_volumes(),
126 }
127 }
128
129 /// Returns given pool's share price in precision 1e8.
130 pub fn get_share_price(&self) -> u128 {
131 match self {
132 Pool::SimplePool(_) => unimplemented!(),
133 Pool::StableSwapPool(pool) => pool.get_share_price(),
134 }
135 }
136
137 /// Swaps given number of token_in for token_out and returns received amount.
138 pub fn swap(
139 &mut self,
140 token_in: &AccountId,
141 amount_in: Balance,
142 token_out: &AccountId,
143 min_amount_out: Balance,
144 admin_fee: AdminFees,
145 ) -> Balance {
146 match self {
147 Pool::SimplePool(pool) => {
148 pool.swap(token_in, amount_in, token_out, min_amount_out, &admin_fee)
149 }
150 Pool::StableSwapPool(pool) => {
151 pool.swap(token_in, amount_in, token_out, min_amount_out, &admin_fee)
152 }
153 }
154 }
155
156 pub fn share_total_balance(&self) -> Balance {
157 match self {
158 Pool::SimplePool(pool) => pool.share_total_balance(),
159 Pool::StableSwapPool(pool) => pool.share_total_balance(),
160 }
161 }
162
163 pub fn share_balances(&self, account_id: &AccountId) -> Balance {
164 match self {
165 Pool::SimplePool(pool) => pool.share_balance_of(account_id),
166 Pool::StableSwapPool(pool) => pool.share_balance_of(account_id),
167 }
168 }
169
170 pub fn share_transfer(&mut self, sender_id: &AccountId, receiver_id: &AccountId, amount: u128) {
171 match self {
172 Pool::SimplePool(pool) => pool.share_transfer(sender_id, receiver_id, amount),
173 Pool::StableSwapPool(pool) => pool.share_transfer(sender_id, receiver_id, amount),
174 }
175 }
176
177 pub fn share_register(&mut self, account_id: &AccountId) {
178 match self {
179 Pool::SimplePool(pool) => pool.share_register(account_id),
180 Pool::StableSwapPool(pool) => pool.share_register(account_id),
181 }
182 }
183
184 pub fn predict_add_stable_liquidity(
185 &self,
186 amounts: &Vec<Balance>,
187 fees: &AdminFees,
188 ) -> Balance {
189 match self {
190 Pool::SimplePool(_) => unimplemented!(),
191 Pool::StableSwapPool(pool) => pool.predict_add_stable_liquidity(amounts, fees),
192 }
193 }
194
195 pub fn predict_remove_liquidity(
196 &self,
197 shares: Balance,
198 ) -> Vec<Balance> {
199 match self {
200 Pool::SimplePool(_) => unimplemented!(),
201 Pool::StableSwapPool(pool) => pool.predict_remove_liquidity(shares),
202 }
203 }
204
205 pub fn predict_remove_liquidity_by_tokens(
206 &self,
207 amounts: &Vec<Balance>,
208 fees: &AdminFees,
209 ) -> Balance {
210 match self {
211 Pool::SimplePool(_) => unimplemented!(),
212 Pool::StableSwapPool(pool) => pool.predict_remove_liquidity_by_tokens(amounts, fees),
213 }
214 }
Tests to Code: 4863 / 5617 = 87 %