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

improve(BundleDataClient): Skip queryHistoricalDepositForFill function for non-infinite expiry deposits #1769

Merged
merged 5 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)) {
nicholaspai marked this conversation as resolved.
Show resolved Hide resolved
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]
nicholaspai marked this conversation as resolved.
Show resolved Hide resolved
) {
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