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

feat(BundleDataClient): Support refunds for pre-fills/slow-fill-requests and duplicate deposits #835

Merged
merged 118 commits into from
Feb 3, 2025

Conversation

nicholaspai
Copy link
Member

@nicholaspai nicholaspai commented Jan 23, 2025

Definitions

  • "pre-fill": any fill that is in a bundle that precedes the bundle containing the matched deposit
  • "pre-slow-fill-request": a mouthful, and any slow fill request in a bundle that precedes the bundle containing the matched deposit
  • "duplicate deposit": a deposit with the same relay hash as an existing one

Core logic for refunding pre-fills:

Evaluate all deposits in the current bundle that were not filled in the current bundle. Figure out whether the deposit was filled, by either:

  • Finding the fill in the spoke pool client's memory, or
  • Querying the fill status on-chain

If there is a fill for this deposit then we need to issue a refund for this fill because the fill occurred in a previous bundle where it might not have been refunded.

We need to use a similar algorithm for creating slow fill leaves for pre-slow-fill-requests with the caveat that we cannot create slow fill leaves for deposits that have expired

Non-determinism for refunding pre-fills

We don't deterministically know whether this pre-fill was refunded in the prior bundle because we don't know for certain what kind of event search window the proposer of the prior bundle used when constructing the bundle.

To illustrate this problem, imagine if a fill and a deposit are sent 10 minutes apart such that the fill is at the end of the current bundle and the deposit is at the beginning of the next. The prior bundle proposer probably would have issued a refund for this fill, but we don't know for certain.

So, one way around this non-determinism is to introduce a new rule to the UMIP:

Do not issue refunds for fills or slow fill leaves where the matched deposit is later than the current bundle block range

This rule makes it always apparent which bundle should include a refund or slow fill leaf for a pre-fill or pre-slow-fill-request.

This will require a UMIP change to this PR

findFillEvents

When we need to query fillStatuses() on-chain to detect whether a deposit corresponds to a very old pre-fill, then we also need to locate that old fill. We assume this is rare and will use the relatively expensive findFillEvents() function which is built off of the existing findFillBlock() function to locate that event.

Duplicate deposits

This PR also adds support for duplicate deposits that are possible to create with unsafeDeposit. Duplicate deposits are added to bundleDeposits for they should be included in runningBalances. Duplicate deposits can be refunded upon expiry but for all deposits, expiry refunds cannot occur once the deposit has been filled.

Due to the presence of pre-fills, we can now no longer instantly include that a deposit submitted in the current bundle that has expired is due a refund. We now need to check its relay status in the case where we don't see a matching fill in our memory.

Unit tests

Can be found here: across-protocol/relayer#2010

…re-slowfill-requests

### Definitions

- "pre-fill": any fill that is in a bundle that precedes the bundle containing the matched deposit
- "pre-slow-fill-request": a mouthful, and any slow fill request in a bundle that precedes the bundle containing the matched deposit

## Core logic for refunding pre-fills:

Evaluate all deposits in the current bundle that were not filled in the current bundle. Figure out whether the deposit was filled, by either:
- Finding the fill in the spoke pool client's memory, or
- Querying the fill status on-chain

If there is a fill for this deposit then we need to issue a refund for this fill because the fill occurred in a previous bundle where it might not have been refunded.

We need to use a similar algorithm for creating slow fill leaves for pre-slow-fill-requests

## Avoiding duplicate refunds for pre-fills

We don't deterministically know whether this pre-fill was refunded in the prior bundle because we don't know for certain what kind of event search window the proposer of the prior bundle used when constructing the bundle.

To illustrate this problem, imagine if a fill and a deposit are sent 10 minutes apart such that the fill is at the end of the current bundle and the deposit is at the beginning of the next. The prior bundle proposer probably would have issued a refund for this fill, but we don't know for certain.

So, one way around this non-determinism is to introduce a new rule to the UMIP:

### Do not issue refunds for fills or slow fill leaves where the matched deposit is later than the current bundle block range

This rule makes it always apparent which bundle should include a refund or slow fill leaf for a pre-fill or pre-slow-fill-request.

This will require a UMIP change to [this PR](UMAprotocol/UMIPs#611)

## TODO

I still need to update the `findFillBlock()` function to return a historical fill for a deposit, because we'll need the FilledRelay's `relayerAddress` or `msg.sender` to credit the refund to (the latter in the case where the relayer address isn't valid on the repayment chain).
@nicholaspai nicholaspai requested review from bmzig and pxrl January 23, 2025 00:52
nicholaspai and others added 2 commits January 23, 2025 08:56
nicholaspai added a commit to across-protocol/relayer that referenced this pull request Jan 23, 2025
This PR should be backwards compatible and deployable to production today

to be paired with across-protocol/sdk#835
I think these are the changes needed but I need to consider more the impact if two deposits expire and they both create slow fill excesses, for example, or other weird edge cases.
@nicholaspai nicholaspai requested a review from bmzig January 23, 2025 23:11
@nicholaspai nicholaspai marked this pull request as draft January 24, 2025 03:26
Copy link
Contributor

@bmzig bmzig left a comment

Choose a reason for hiding this comment

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

One comment.

Try to consolidate calls to verifyFillRepayment and refactor it into some utility functions we can use as additional asserts in the BundleDataClient
@nicholaspai nicholaspai requested a review from bmzig February 1, 2025 21:24
@nicholaspai nicholaspai requested a review from bmzig February 3, 2025 16:12
return;
}
assert(
chainIsEvm(deposit.destinationChainId) && isValidEvmAddress(deposit.recipient),
Copy link
Contributor

@bmzig bmzig Feb 3, 2025

Choose a reason for hiding this comment

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

If you are adding this assert, I believe you will also need to change _canCreateSlowFillLeaf to check for a valid recipient since somebody can supply garbage to a deposit and request a slow fill for that. If that happened, we would just continuously fail on this assert.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a good point I'm going to revert 5c32bd8

@nicholaspai
Copy link
Member Author

@bmzig I added bundleInvalidSlowFIllRequests logging here cc9ebfc

@nicholaspai nicholaspai requested a review from bmzig February 3, 2025 17:07
@nicholaspai nicholaspai merged commit 2e3fbe4 into master Feb 3, 2025
4 checks passed
nicholaspai added a commit to across-protocol/relayer that referenced this pull request Feb 3, 2025
)

* feat(Dataworker): Support pre-fill refunds

This PR should be backwards compatible and deployable to production today

to be paired with across-protocol/sdk#835

* Finish new tests

* Update Dataworker.buildRoots.ts

* Revert "Update Dataworker.buildRoots.ts"

This reverts commit 40ad15f.

* Add test against duplicate deposits

* Add unit tests for duplicate deposits

* Import beta sdk

* import sdk

* update import

* Update package.json

* Update config.yml

* wip

* Fix tests

* Update SpokePoolUtils.ts

* Update SpokePoolUtils.ts

* Update Dataworker.loadData.prefill.ts

* Add tests for zero value deposits

* Split up tests to speed up CI

* import

* Update package.json

* Update yarn.lock

* import

* Fix tests

* fix

* bump

* Remove mocked version bump in non-prefill tests

* wip

* lint

* bump

* bump

* fix

* import

* fix

* Update Dataworker.loadData.fill.ts

* Fix tests

* move some bytes32 invalid test cases to pre-fills because they hit pre-fill logic

* WIP

* Update Dataworker.loadData.prefill.ts

* update

* WIP

* fix

* wip

* update

* fix

* Update Dataworker.loadData.prefill.ts

* fix

* bump package to new duplicate refund version

* Add test cases for historical deposit query when matched deposit is in future bundle

* fix

* Update Dataworker.loadData.fill.ts

* Update Dataworker.loadData.fill.ts

* pay refunds to pre-filler unless slow fill

* Update Dataworker.loadData.prefill.ts

* Update Dataworker.loadData.prefill.ts

* fix

* Add verifyFillRepayment test for pre fills

* add asserts

* wip

* 34

* fix test

* 4.0.0

* Update Constants.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants