Skip to content

Commit

Permalink
refactor: Simplify FillUtils getUnfilledDeposits() (#1249)
Browse files Browse the repository at this point in the history
This is an incremental change to drop some unneeded members from the
return type, and to return an Object of destination chain => unfilled
deposits array. This permits the caller to keep the unfilled deposits
segregated, which fits future use cases pretty well.
  • Loading branch information
pxrl authored Mar 4, 2024
1 parent 2ba7adf commit 8c307af
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 46 deletions.
17 changes: 8 additions & 9 deletions src/monitor/Monitor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { utils as sdkUtils } from "@across-protocol/sdk-v2";
import { BalanceAllocator } from "../clients";
import { spokePoolClientsToProviders } from "../common";
import {
Expand Down Expand Up @@ -186,15 +185,15 @@ export class Monitor {

// Group unfilled amounts by chain id and token id.
const unfilledAmountByChainAndToken: { [chainId: number]: { [tokenAddress: string]: BigNumber } } = {};
for (const deposit of unfilledDeposits) {
const chainId = deposit.deposit.destinationChainId;
const outputToken = sdkUtils.getDepositOutputToken(deposit.deposit);
Object.entries(unfilledDeposits).forEach(([_destinationChainId, deposits]) => {
const chainId = Number(_destinationChainId);
unfilledAmountByChainAndToken[chainId] ??= {};
unfilledAmountByChainAndToken[chainId][outputToken] ??= bnZero;
unfilledAmountByChainAndToken[chainId][outputToken] = unfilledAmountByChainAndToken[chainId][outputToken].add(
deposit.unfilledAmount
);
}

deposits.forEach(({ deposit: { outputToken, outputAmount } }) => {
const unfilledAmount = unfilledAmountByChainAndToken[chainId][outputToken] ?? bnZero;
unfilledAmountByChainAndToken[chainId][outputToken] = unfilledAmount.add(outputAmount);
});
});

let mrkdwn = "";
for (const [chainIdStr, amountByToken] of Object.entries(unfilledAmountByChainAndToken)) {
Expand Down
5 changes: 4 additions & 1 deletion src/relayer/Relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ export class Relayer {
const { configStoreClient, hubPoolClient, spokePoolClients, acrossApiClient } = this.clients;
const { relayerTokens, ignoredAddresses, acceptInvalidFills } = this.config;

const unfilledDeposits = await getUnfilledDeposits(spokePoolClients, hubPoolClient, this.config.maxRelayerLookBack);
// Flatten unfilledDeposits for now. @todo: Process deposits in parallel by destination chain.
const unfilledDeposits = Object.values(
await getUnfilledDeposits(spokePoolClients, hubPoolClient, this.config.maxRelayerLookBack)
).flat();

const maxVersion = configStoreClient.configStoreVersion;
return sdkUtils.filterAsync(unfilledDeposits, async ({ deposit, version, invalidFills }) => {
Expand Down
49 changes: 23 additions & 26 deletions src/utils/FillUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,6 @@ export function getFillsInRange(
export type RelayerUnfilledDeposit = {
deposit: V3DepositWithBlock;
version: number;
unfilledAmount: BigNumber;
fillCount: number;
invalidFills: Fill[];
};

Expand All @@ -273,8 +271,8 @@ export async function getUnfilledDeposits(
spokePoolClients: SpokePoolClientsByChain,
hubPoolClient: HubPoolClient,
depositLookBack?: number
): Promise<RelayerUnfilledDeposit[]> {
const unfilledDeposits: RelayerUnfilledDeposit[] = [];
): Promise<{ [chainId: number]: RelayerUnfilledDeposit[] }> {
const unfilledDeposits: { [chainId: number]: RelayerUnfilledDeposit[] } = {};
const chainIds = Object.values(spokePoolClients).map(({ chainId }) => chainId);
let earliestBlockNumbers = Object.values(spokePoolClients).map(({ deploymentBlock }) => deploymentBlock);

Expand All @@ -291,31 +289,30 @@ export async function getUnfilledDeposits(
}

// Iterate over each chainId and check for unfilled deposits.
chainIds.forEach((originChainId, idx) => {
const originClient = spokePoolClients[originChainId];
chainIds.forEach((destinationChainId, idx) => {
const destinationClient = spokePoolClients[destinationChainId];
const earliestBlockNumber = earliestBlockNumbers[idx];

for (const destinationChain of chainIds.filter((chainId) => chainId !== originChainId)) {
// Find all unfilled deposits for the current loops originChain -> destinationChain. Note that this also
// validates that the deposit is filled "correctly" for the given deposit information. This includes validation
// of the all deposit -> relay props, the realizedLpFeePct and the origin->destination token mapping.
const destinationClient = spokePoolClients[destinationChain];
const deposits = originClient
.getDepositsForDestinationChain(destinationChain)
.filter(sdkUtils.isV3Deposit<V3DepositWithBlock, V2DepositWithBlock>);
unfilledDeposits[destinationChainId] = chainIds
.filter((chainId) => chainId !== destinationChainId)
.map((originChainId) => {
const originClient = spokePoolClients[originChainId];
// Find all unfilled deposits for the current loops originChain -> destinationChain. Note that this also
// validates that the deposit is filled "correctly" for the given deposit information. This includes validation
// of the all deposit -> relay props, the realizedLpFeePct and the origin->destination token mapping.
const deposits = originClient
.getDepositsForDestinationChain(destinationChainId)
.filter(sdkUtils.isV3Deposit<V3DepositWithBlock, V2DepositWithBlock>);

const unfilledDepositsForDestinationChain = deposits
.filter((deposit) => deposit.blockNumber >= earliestBlockNumber)
.map((deposit) => {
const version = hubPoolClient.configStoreClient.getConfigStoreVersionForTimestamp(deposit.quoteTimestamp);
return { ...destinationClient.getValidUnfilledAmountForDeposit(deposit), deposit, version };
});

// Remove any deposits that have no unfilled amount and append the remaining deposits to unfilledDeposits array.
unfilledDeposits.push(
...unfilledDepositsForDestinationChain.filter((deposit) => deposit.unfilledAmount.gt(bnZero))
);
}
return deposits
.filter((deposit) => deposit.blockNumber >= earliestBlockNumber)
.map((deposit) => {
const version = hubPoolClient.configStoreClient.getConfigStoreVersionForTimestamp(deposit.quoteTimestamp);
return { ...destinationClient.getValidUnfilledAmountForDeposit(deposit), deposit, version };
})
.filter(({ unfilledAmount }) => unfilledAmount.gt(bnZero));
})
.flat();
});

return unfilledDeposits;
Expand Down
21 changes: 11 additions & 10 deletions test/Relayer.UnfilledDeposits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,8 @@ describe("Relayer: Unfilled Deposits", async function () {
await Promise.all([spokePool_1, spokePool_2].map((spokePool) => spokePool.setCurrentTime(currentTime)));
await updateAllClients();

_getUnfilledDeposits = async (): Promise<RelayerUnfilledDeposit[]> => {
return await getUnfilledDeposits(relayerInstance.clients.spokePoolClients, hubPoolClient);
};
_getUnfilledDeposits = async (): Promise<RelayerUnfilledDeposit[]> =>
Object.values(await getUnfilledDeposits(relayerInstance.clients.spokePoolClients, hubPoolClient)).flat();
unfilledDeposits = [];

const tokenBalance = await erc20_1.balanceOf(depositor.address);
Expand All @@ -181,13 +180,15 @@ describe("Relayer: Unfilled Deposits", async function () {
expect(unfilledDeposits)
.excludingEvery(["realizedLpFeePct", "quoteBlockNumber"])
.to.deep.equal(
deposits.map((deposit) => ({
unfilledAmount: deposit.outputAmount,
deposit,
fillCount: 0,
invalidFills: [],
version: configStoreClient.configStoreVersion,
}))
deposits
.sort((a, b) => (a.destinationChainId > b.destinationChainId ? 1 : -1))
.map((deposit) => ({
unfilledAmount: deposit.outputAmount,
deposit,
fillCount: 0,
invalidFills: [],
version: configStoreClient.configStoreVersion,
}))
);
});

Expand Down

0 comments on commit 8c307af

Please sign in to comment.