Skip to content

Commit

Permalink
improve(BundleDataClient): Skip queryHistoricalDepositForFill funct…
Browse files Browse the repository at this point in the history
…ion for non-infinite expiry deposits (#1769)
  • Loading branch information
nicholaspai committed Aug 26, 2024
1 parent d125f7f commit aa1ec0d
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 36 deletions.
18 changes: 16 additions & 2 deletions src/clients/BundleDataClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
isDefined,
toBN,
} from "../utils";
import { Clients } from "../common";
import { Clients, INFINITE_FILL_DEADLINE } from "../common";
import {
getBlockRangeForChain,
getImpliedBundleBlockRanges,
Expand Down Expand Up @@ -869,7 +869,16 @@ export class BundleDataClient {

// Since there was no deposit matching the relay hash, we need to do a historical query for an
// older deposit in case the spoke pool client's lookback isn't old enough to find the matching deposit.
// We can skip this step if the fill's fill deadline is not infinite, because we can assume that the
// spoke pool clients have loaded deposits old enough to cover all fills with a non-infinite fill deadline.
if (fill.blockNumber >= destinationChainBlockRange[0]) {
// Fill has a non-infinite expiry, and we can assume our spoke pool clients have old enough deposits
// to conclude that this fill is invalid if we haven't found a matching deposit in memory, so
// skip the historical query.
if (!INFINITE_FILL_DEADLINE.eq(fill.fillDeadline)) {
bundleInvalidFillsV3.push(fill);
return;
}
const historicalDeposit = await queryHistoricalDepositForFill(originClient, fill);
if (!historicalDeposit.found) {
bundleInvalidFillsV3.push(fill);
Expand Down Expand Up @@ -963,7 +972,12 @@ export class BundleDataClient {

// Since there was no deposit matching the relay hash, we need to do a historical query for an
// older deposit in case the spoke pool client's lookback isn't old enough to find the matching deposit.
if (slowFillRequest.blockNumber >= destinationChainBlockRange[0]) {
// We can skip this step if the deposit's fill deadline is not infinite, because we can assume that the
// spoke pool clients have loaded deposits old enough to cover all fills with a non-infinite fill deadline.
if (
INFINITE_FILL_DEADLINE.eq(slowFillRequest.fillDeadline) &&
slowFillRequest.blockNumber >= destinationChainBlockRange[0]
) {
const historicalDeposit = await queryHistoricalDepositForFill(originClient, slowFillRequest);
if (!historicalDeposit.found) {
// TODO: Invalid slow fill request. Maybe worth logging.
Expand Down
5 changes: 4 additions & 1 deletion src/common/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CHAIN_IDs, TOKEN_SYMBOLS_MAP, ethers, Signer, Provider, ZERO_ADDRESS } from "../utils";
import { CHAIN_IDs, TOKEN_SYMBOLS_MAP, ethers, Signer, Provider, ZERO_ADDRESS, bnUint32Max } from "../utils";
import {
BaseBridgeAdapter,
OpStackDefaultERC20Bridge,
Expand Down Expand Up @@ -31,6 +31,9 @@ export const CONFIG_STORE_VERSION = 4;

export const RELAYER_MIN_FEE_PCT = 0.0001;

// max(uint256) - 1
export const INFINITE_FILL_DEADLINE = bnUint32Max;

// Target ~4 hours
export const MAX_RELAYER_DEPOSIT_LOOK_BACK = 4 * 60 * 60;

Expand Down
23 changes: 17 additions & 6 deletions test/Dataworker.loadData.fill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { MockConfigStoreClient, MockHubPoolClient, MockSpokePoolClient } from ".
import { interfaces, utils as sdkUtils } from "@across-protocol/sdk";
import { cloneDeep } from "lodash";
import { CombinedRefunds } from "../src/dataworker/DataworkerUtils";
import { INFINITE_FILL_DEADLINE } from "../src/common";

let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract;
let l1Token_1: Contract;
Expand Down Expand Up @@ -404,15 +405,18 @@ describe("Dataworker: Load data used in all functions", async function () {
// For this test, we need to actually send a deposit on the spoke pool
// because queryHistoricalDepositForFill eth_call's the contract.

// Send a deposit.
// Send a legacy deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down Expand Up @@ -442,15 +446,19 @@ describe("Dataworker: Load data used in all functions", async function () {
// For this test, we need to actually send a deposit on the spoke pool
// because queryHistoricalDepositForFill eth_call's the contract.

// Send a deposit.
// Send a legacy deposit where the fill deadline is infinite, so we can test the bundle data client uses
// queryHistoricalDepositForFill to find the deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();
// Construct a spoke pool client with a small search range that would not include the deposit.
Expand Down Expand Up @@ -499,15 +507,18 @@ describe("Dataworker: Load data used in all functions", async function () {
// For this test, we need to actually send a deposit on the spoke pool
// because queryHistoricalDepositForFill eth_call's the contract.

// Send a deposit.
// Send a legacy deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down
36 changes: 26 additions & 10 deletions test/Dataworker.loadData.slowFill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { getCurrentTime, Event, toBNWei, assert, ZERO_ADDRESS } from "../src/uti
import { MockConfigStoreClient, MockHubPoolClient, MockSpokePoolClient } from "./mocks";
import { interfaces, utils as sdkUtils } from "@across-protocol/sdk";
import { cloneDeep } from "lodash";
import { INFINITE_FILL_DEADLINE } from "../src/common";

describe("BundleDataClient: Slow fill handling & validation", async function () {
let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract;
Expand Down Expand Up @@ -372,15 +373,18 @@ describe("BundleDataClient: Slow fill handling & validation", async function ()
// For this test, we need to actually send a deposit on the spoke pool
// because queryHistoricalDepositForFill eth_call's the contract.

// Send a deposit.
// Send a legacy deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down Expand Up @@ -469,15 +473,18 @@ describe("BundleDataClient: Slow fill handling & validation", async function ()
// For this test, we need to actually send a deposit on the spoke pool
// because queryHistoricalDepositForFill eth_call's the contract.

// Send a deposit.
// Send a legacy deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down Expand Up @@ -507,7 +514,7 @@ describe("BundleDataClient: Slow fill handling & validation", async function ()
// For this test, we need to actually send a deposit on the spoke pool
// because queryHistoricalDepositForFill eth_call's the contract.

// Send a deposit. We'll set output token to a random token to invalidate the slow fill request (e.g.
// Send a legacy deposit. We'll set output token to a random token to invalidate the slow fill request (e.g.
// input and output are not "equivalent" tokens)
const invalidOutputToken = erc20_1;
const depositObject = await depositV3(
Expand All @@ -517,7 +524,10 @@ describe("BundleDataClient: Slow fill handling & validation", async function ()
erc20_1.address,
amountToDeposit,
invalidOutputToken.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down Expand Up @@ -656,15 +666,18 @@ describe("BundleDataClient: Slow fill handling & validation", async function ()
await mockConfigStore.update();
(spokePoolClient_1 as any).configStoreClient = mockConfigStore;
(spokePoolClient_2 as any).configStoreClient = mockConfigStore;
// Send a deposit.
// Send a legacy deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down Expand Up @@ -701,15 +714,18 @@ describe("BundleDataClient: Slow fill handling & validation", async function ()
await mockConfigStore.update();
(spokePoolClient_1 as any).configStoreClient = mockConfigStore;
(spokePoolClient_2 as any).configStoreClient = mockConfigStore;
// Send a deposit.
// Send a legacy deposit.
const depositObject = await depositV3(
spokePool_1,
destinationChainId,
depositor,
erc20_1.address,
amountToDeposit,
erc20_2.address,
amountToDeposit
amountToDeposit,
{
fillDeadline: INFINITE_FILL_DEADLINE.toNumber(),
}
);
const depositBlock = await spokePool_1.provider.getBlockNumber();

Expand Down
54 changes: 37 additions & 17 deletions test/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
sampleRateModel,
} from "../constants";
import { SpokePoolDeploymentResult, SpyLoggerResult } from "../types";
import { INFINITE_FILL_DEADLINE } from "../../src/common";

export {
SpyTransport,
Expand Down Expand Up @@ -286,27 +287,42 @@ export async function depositV3(
const quoteTimestamp = opts.quoteTimestamp ?? spokePoolTime;
const message = opts.message ?? constants.EMPTY_MESSAGE;
const fillDeadline = opts.fillDeadline ?? spokePoolTime + fillDeadlineBuffer;
const isLegacyDeposit = INFINITE_FILL_DEADLINE.eq(fillDeadline);
const exclusivityDeadline = opts.exclusivityDeadline ?? 0;
const exclusiveRelayer = opts.exclusiveRelayer ?? ZERO_ADDRESS;

const [originChainId, txnResponse] = await Promise.all([
spokePool.chainId(),
spokePool
.connect(signer)
.depositV3(
depositor,
recipient,
inputToken,
outputToken,
inputAmount,
outputAmount,
destinationChainId,
exclusiveRelayer,
quoteTimestamp,
fillDeadline,
exclusivityDeadline,
message
),
isLegacyDeposit
? spokePool
.connect(signer)
.depositFor(
depositor,
recipient,
inputToken,
inputAmount,
destinationChainId,
inputAmount.sub(outputAmount).mul(toWei(1)).div(inputAmount),
quoteTimestamp,
message,
0
)
: spokePool
.connect(signer)
.depositV3(
depositor,
recipient,
inputToken,
outputToken,
inputAmount,
outputAmount,
destinationChainId,
exclusiveRelayer,
quoteTimestamp,
fillDeadline,
exclusivityDeadline,
message
),
]);
const txnReceipt = await txnResponse.wait();

Expand All @@ -317,14 +333,18 @@ export async function depositV3(
const { blockNumber, transactionHash, transactionIndex } = txnReceipt;
const { logIndex } = eventLog;

return {
const depositObject = {
originChainId: Number(originChainId),
blockNumber,
transactionHash,
transactionIndex,
logIndex,
...spreadEvent(args),
};
if (isLegacyDeposit) {
depositObject.outputToken = outputToken;
}
return depositObject;
}

export async function updateDeposit(
Expand Down

0 comments on commit aa1ec0d

Please sign in to comment.