From a7615d0c68d847cfd8a42c992df32390b5931e01 Mon Sep 17 00:00:00 2001 From: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Date: Thu, 2 Jan 2025 10:49:34 -0500 Subject: [PATCH] feat(BundleDataClient): Remove 0-value deposits and fills and 0-value empty-message slow fills (#800) --- package.json | 2 +- .../BundleDataClient/BundleDataClient.ts | 19 +++++++++++++++++-- src/utils/DepositUtils.ts | 12 ++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 62577d2ea..f1eefac80 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@across-protocol/sdk", "author": "UMA Team", - "version": "3.3.31", + "version": "3.3.32", "license": "AGPL-3.0", "homepage": "https://docs.across.to/reference/sdk", "files": [ diff --git a/src/clients/BundleDataClient/BundleDataClient.ts b/src/clients/BundleDataClient/BundleDataClient.ts index 22c7ecb34..fd992c95d 100644 --- a/src/clients/BundleDataClient/BundleDataClient.ts +++ b/src/clients/BundleDataClient/BundleDataClient.ts @@ -31,6 +31,7 @@ import { isSlowFill, mapAsync, bnUint32Max, + isZeroValueDeposit, } from "../../utils"; import winston from "winston"; import { @@ -778,6 +779,9 @@ export class BundleDataClient { continue; } originClient.getDepositsForDestinationChain(destinationChainId).forEach((deposit) => { + if (isZeroValueDeposit(deposit)) { + return; + } depositCounter++; const relayDataHash = this.getRelayHashFromEvent(deposit); if (v3RelayHashes[relayDataHash]) { @@ -793,6 +797,14 @@ export class BundleDataClient { slowFillRequest: undefined, }; + // Once we've saved the deposit hash into v3RelayHashes, then we can exit early here if the inputAmount + // is 0 because there can be no expired amount to refund and no unexecutable slow fill amount to return + // if this deposit did expire. Input amount can only be zero at this point if the message is non-empty, + // but the message doesn't matter for expired deposits and unexecutable slow fills. + if (deposit.inputAmount.eq(0)) { + return; + } + // If deposit block is within origin chain bundle block range, then save as bundle deposit. // If deposit is in bundle and it has expired, additionally save it as an expired deposit. // If deposit is not in the bundle block range, then save it as an older deposit that @@ -840,7 +852,10 @@ export class BundleDataClient { await forEachAsync( destinationClient .getFillsForOriginChain(originChainId) - .filter((fill) => fill.blockNumber <= destinationChainBlockRange[1]), + // We can remove fills for deposits with input amount equal to zero because these will result in 0 refunded + // tokens to the filler. We can't remove non-empty message deposit here in case there is a slow fill + // request for the deposit, we'd want to see the fill took place. + .filter((fill) => fill.blockNumber <= destinationChainBlockRange[1] && !isZeroValueDeposit(fill)), async (fill) => { const relayDataHash = this.getRelayHashFromEvent(fill); fillCounter++; @@ -933,7 +948,7 @@ export class BundleDataClient { await forEachAsync( destinationClient .getSlowFillRequestsForOriginChain(originChainId) - .filter((request) => request.blockNumber <= destinationChainBlockRange[1]), + .filter((request) => request.blockNumber <= destinationChainBlockRange[1] && !isZeroValueDeposit(request)), async (slowFillRequest: SlowFillRequestWithBlock) => { const relayDataHash = this.getRelayHashFromEvent(slowFillRequest); diff --git a/src/utils/DepositUtils.ts b/src/utils/DepositUtils.ts index 59ab124c0..5dd97aec2 100644 --- a/src/utils/DepositUtils.ts +++ b/src/utils/DepositUtils.ts @@ -125,6 +125,18 @@ export async function queryHistoricalDepositForFill( }; } +/** + * Returns true if filling this deposit (as a slow or fast fill) or refunding it would not change any state + * on-chain. The dataworker functions can use this to conveniently filter out useless deposits. + * @dev The reason we allow a 0-input deposit to have a non-empty message is that the message might be used + * to pay the filler in an indirect way so it might have economic value as a fast or slow fill. + * @param deposit Deposit to check. + * @returns True if deposit's input amount is 0 and message is empty. + */ +export function isZeroValueDeposit(deposit: Pick): boolean { + return deposit.inputAmount.eq(0) && isMessageEmpty(deposit.message); +} + /** * Determines if a message is empty or not. * @param message The message to check.