Skip to content

Conversation

@tilacog
Copy link
Contributor

@tilacog tilacog commented Jan 14, 2026

Description

This PR follows up on #4029 and introduces a trait‑based architecture for the refunder crate. By decoupling the RefundService from concrete database and blockchain implementations, we can now write unit tests without relying on (heavyweight) integration tests.

Changes

  • Added a new traits.rs module that defines DbRead, ChainRead, and ChainWrite traits to abstract the two main boundaries of the system.
  • Created an infra/ module housing the previous concrete implementations of those traits:
    • AlloyChain implements ChainRead
    • Postgres implements DbRead
  • Made RefundService generic over those traits, so we can use mocks for unit testing it (and thes real/production implementations) as needed.
  • Extracted identify_uids_refunding_status into its own function, to simplify testing.
  • Moved the RefundStatus enum into traits.rs so it lives alongside the related abstractions.
  • Reorganized the service construction inside run() for clearer flow.
  • Added a suite of unit tests that use mocks to cover a variety of scenarios.

How to test

Run the unit tests with:

cargo nextest run -p refunder

@tilacog tilacog marked this pull request as ready for review January 15, 2026 12:41
@tilacog tilacog requested a review from a team as a code owner January 15, 2026 12:41
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a well-executed trait-based architecture to the refunder crate, significantly improving its testability by decoupling the RefundService from concrete database and blockchain implementations. The changes are clean, well-structured, and accompanied by a comprehensive suite of unit tests. My feedback includes an observation regarding potential inconsistency in order data fetching logic, which is suggested to be addressed in a follow-up PR to maintain separation of concerns.

Copy link
Contributor

@jmg-duarte jmg-duarte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, this code is so much easier to read!

@tilacog tilacog added this pull request to the merge queue Jan 15, 2026
@jmg-duarte jmg-duarte removed this pull request from the merge queue due to a manual request Jan 15, 2026
@tilacog tilacog requested a review from squadgazzz January 15, 2026 18:12
Copy link
Contributor

@squadgazzz squadgazzz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the PR, but it introduces some complexity and +1k lines of code, so I wanted to better understand the reasoning behind it.

Is there something we can't test with existing e2e tests? Where will unit tests help better? Historically, e2e tests in the services repo have been preferred over unit tests due to a less artificial environment and because unit tests require more time to maintain.

@tilacog
Copy link
Contributor Author

tilacog commented Jan 16, 2026

Is there something we can't test with existing e2e tests?
Where will unit tests help better?

We briefly discussed that unit tests might help alleviate the expensive e2e test runs, so I'd say we can scale up unit tests without compromising CI time as much as with e2e tests.

So, in the future, it might suffice to just add a new unit test than to [re]write an e2e test.

@tilacog tilacog requested a review from squadgazzz January 21, 2026 12:47
@@ -0,0 +1,142 @@
//! Trait definitions for database and blockchain access.
#![allow(async_fn_in_trait)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not using async-trait then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer avoiding third-party dependencies where possible. I reckon there are some tradeoffs, but I don't think they play a big role in this case.


/// Blockchain write operations.
#[cfg_attr(test, mockall::automock)]
pub trait ChainWrite: Send + Sync {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this trait have only one implementation? Do we need this trait then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the new traits have one "production" implementation, plus the one generated by automock.
We need the traits to write more expressive unit tests.

/// contains UIDs but no order details feels off. Possible fixes:
/// 1. Skip the submission entirely when `encoded_ethflow_orders` is empty.
/// 2. Return an error if *all* order‑data lookups fail.
/// 3. Filter the UID list so it only includes IDs with successful lookups.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, maybe that should be the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got a little confused trying to mirror the refunder’s behavior in this test, and I agree we should make it better.

I left it out of this PR to keep the scope focused, so I believe we can raise it and discuss improvements in a separate issue.

.get_refundable_orders(
block_time,
self.min_validity_duration,
self.min_price_deviation_bps as f64 / 10_000.0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10_000.0 should probably be extracted into a constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed that in 688ea06

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants