Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute partner fees #52

Merged
merged 28 commits into from
Sep 6, 2024
Merged

Compute partner fees #52

merged 28 commits into from
Sep 6, 2024

Conversation

harisang
Copy link
Contributor

@harisang harisang commented Sep 4, 2024

This PR aims to distinguish between partner and protocol fees, instead of labeling everything as protocol fees.

@harisang harisang requested a review from fhenneke September 4, 2024 14:35
src/fees/compute_fees.py Outdated Show resolved Hide resolved
@@ -21,17 +21,39 @@
class Trade:
"""Class for"""

order_uid: HexBytes
Copy link
Contributor

Choose a reason for hiding this comment

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

This code now deviates sufficiently from the code in the circuit breaker to require actual tests.

sell_token_clearing_price: int
buy_token_clearing_price: int
fee_policies: list["FeePolicy"]
def __init__(
Copy link
Contributor

Choose a reason for hiding this comment

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

a __post_init__ method could be used instead to set the remaining fields which require computation.

src/fees/compute_fees.py Outdated Show resolved Hide resolved
src/fees/compute_fees.py Outdated Show resolved Hide resolved
src/fees/compute_fees.py Outdated Show resolved Hide resolved
src/fees/compute_fees.py Outdated Show resolved Hide resolved
src/fees/compute_fees.py Outdated Show resolved Hide resolved
i = 0
self.protocol_fee = 0
self.partner_fee = 0
if self.fee_policies:
Copy link
Contributor

@fhenneke fhenneke Sep 4, 2024

Choose a reason for hiding this comment

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

Is this line required? If not, it should be removed. If yes, a small comment might help understand why it is needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is line 98 that needs to execute after the for-loop finishes, but it only makes sense if there was at least one fee policy.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, i see. But to me it is simpler to write

        partner_fee = 0
        for i, fee_policy in enumerate(reversed(self.fee_policies)):
            raw_trade = fee_policy.reverse_protocol_fee(raw_trade)
            ## we assume that partner fee is the last to be applied
            if i == 0 and self.partner_fee_recipient is not NULL_ADDRESS:
                partner_fee = raw_trade.surplus() - self.surplus()
        total_protocol_fee = raw_trade.surplus() - self.surplus()

The other two initializations are not required.

That part of the code might even benefit from a function

    def partner_fee(self):
        if not self.fee_policies or self.partner_fee_recipient is NULL_ADDRESS:
            return 0
        # we assume that partner fee is the last to be applied
        fee_policy = self.fee_policies[-1]
        raw_trade = deepcopy(self)
        raw_trade = fee_policy.reverse_protocol_fee(raw_trade)
        return raw_trade.surplus() - self.surplus()

and then just

        partner_fee = self.partner_fee()
        total_protocol_fee = self.total_protocol_fee()

The small loss in efficiency should not matter compared to the increase in readability. (Though you might disagree on the readability, then feel free to ignore).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually you are right and my concern was not really justified. I simplified the code and followed your first suggestion.

@harisang harisang marked this pull request as ready for review September 5, 2024 09:51
@harisang harisang requested a review from fhenneke September 5, 2024 09:56
src/helpers/database.py Outdated Show resolved Hide resolved
for trade in settlement_data.trades:
# protocol fees
protocol_fee_amount = trade.protocol_fee()
protocol_fee_amount = trade.total_protocol_fee - trade.partner_fee
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that this also breaks the convention (maybe we should!) with what we upload to Dune.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed but somehow it makes sense to have a table where when we look for a protocol fee, this is indeed the protocol fee and not something that potentially includes other fees there as well. So i would like to keep this here to be as explicit as possible in the db, I.e., have:

  • network fee in sell token
  • protocol fee in surplus token
  • partner fee, if any, in surplus token

And there are no subtractions or anything like that. Protocol fee goes to the DAO, partner fee goes to the partner, and network fee to solvers, and that's it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that the convention on Dune is a bit misleading. Maybe we should switch it there as well. I am not familiar with the legal accounting requirements, though. Partner fees might be revenue with an associated cost.

Regarding partner fees going to partners: unfortunately that is not so easy as we take a cut. But generally I agree with this distinction. I expect the protocol fee mess to become even more ugly in the future, so having a reasonable intermediate representation sound most sustainable.

In terms of consistency with backend: the planned changes might include protocol fees per fee policy. So it is even one level more fine grained in case we go crazy with stacking protocol fees (which I expect to happen).

Comment on lines +483 to +491
def compute_all_fees_of_batch(
tx_hash: HexBytes,
) -> tuple[
dict[str, tuple[str, int]],
dict[str, tuple[str, int, str]],
dict[str, tuple[str, int]],
]:
orderbook_api = OrderbookFetcher()
settlement_data = orderbook_api.get_all_data(tx_hash)
Copy link
Contributor

Choose a reason for hiding this comment

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

Combining the functions compute_fee_imbalances and batch_fee_imbalances entangles data fetching and fee computations. This makes it more difficult to to test the new convention for protocol fees.

Copy link
Contributor

@fhenneke fhenneke left a comment

Choose a reason for hiding this comment

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

All major issues have been addressed, I think.

The one thing which still is worrying to me is that there are no tests and the code has diverged quite a bit from the circuit breaker code.

I would say that the minimum would be to have an end-to-end tests for a single hash where we know the correct values. Those values are then just hard coded in the test. This requires to check single example (like was done multiple times already I suspect). It would also detect unexpected changes, should we change some of the fee code.

Copy link

socket-security bot commented Sep 6, 2024

New dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
pypi/[email protected] environment, eval, filesystem, network, shell, unsafe 0 5.78 MB The_Compiler, anatoly, flub, ...4 more

View full report↗︎

@harisang
Copy link
Contributor Author

harisang commented Sep 6, 2024

Added a test which might be useful. Merging for now as i would like to test this PR through the weekend.

@harisang harisang merged commit a62813b into main Sep 6, 2024
3 checks passed
@harisang harisang mentioned this pull request Sep 6, 2024
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.

2 participants