Test suite
In our opinion, test coverage for Tradoor is not sufficient.
When building a complex contract ecosystem with multiple moving parts and dependencies, comprehensive testing is essential. This includes testing for both positive and negative scenarios. Positive tests should verify that each function's side effect is as expected, while negative tests should cover every revert, preferably in every logical branch.
It is important to test the invariants required for ensuring security and also verify mathematical properties from the project's specifications.
Few tests cover negative scenarios
First, while all of the major internal functions are tested with positive scenarios, there are few tests for negative scenarios.
Good test coverage has multiple effects.
It finds bugs and design flaws early (preaudit or prerelease).
It gives insight into areas for optimization (e.g., gas cost).
It displays code maturity.
It bolsters customer trust in your product.
It improves understanding of how the code functions, integrates, and operates — for developers and auditors alike.
It increases development velocity long-term.
The last point seems contradictory, given the time investment to create and maintain tests. To expand upon that, tests help developers trust their own changes. It is difficult to know if a code refactor — or even just a small one-line fix — breaks something if there are no tests. This is especially true for new developers or those returning to the code after a prolonged absence. Tests have your back here. They are an indicator that the existing functionality most likely was not broken by your change to the code.
Throughout section , we document a great number of untested negative scenarios (and in some cases, untested positive scenarios). We recommend walking through every instruction and writing the missing tests where possible.
Contract complexity warrants more positive-scenario tests
Additionally, while there are integration tests for most handlers, these are too few given the complexity of the contract state; most of the callable code greatly depends on the current contract state (the global LP position, open orders, etc.).
We recommend writing tests that hardcode various possible/plausible contract states and testing each of the important functions (order creation, liquidation, etc.) against these states.
Finally, we recommend fuzz testing the contract to simulate users interacting with the contract in various ways. This is a great way to find edge cases and bugs that are difficult to identify through manual testing.