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

refactor: Replace ethers Event with Log #738

Merged
merged 6 commits into from
Sep 20, 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
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ module.exports = {
{
"patterns": [
{ group: ["@ethersproject/bignumber"], message: "Use 'src/utils/BigNumberUtils' instead" },
{ group: ["@ethersproject/contracts"], importNames: ["Event"], message: "Use Log from 'src/interfaces/Common' instead" },
],
"paths": [
{ name: "ethers", importNames: ["BigNumber"], message: "Use 'src/utils/BigNumberUtils' instead" }
{ name: "ethers", importNames: ["BigNumber"], message: "Use 'src/utils/BigNumberUtils' instead" },
{ name: "ethers", importNames: ["Event"], message: "Use Log from 'src/interfaces/Common' instead" }
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@across-protocol/sdk",
"author": "UMA Team",
"version": "3.1.36",
"version": "3.2.0",
"license": "AGPL-3.0",
"homepage": "https://docs.across.to/reference/sdk",
"files": [
Expand Down
19 changes: 9 additions & 10 deletions src/clients/AcrossConfigStoreClient/AcrossConfigStoreClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { utils, across } from "@uma/sdk";
import assert from "assert";
import { Contract, Event } from "ethers";
import { Contract } from "ethers";
import winston from "winston";
import { isError } from "../../typeguards";
import {
Expand All @@ -14,7 +14,6 @@ import {
paginatedEventQuery,
sortEventsAscendingInPlace,
sortEventsDescending,
spreadEvent,
spreadEventWithBlockNumber,
toBN,
utf8ToHex,
Expand All @@ -25,8 +24,10 @@ import {
DisabledChainsUpdate,
GlobalConfigUpdate,
LiteChainsIdListUpdate,
Log,
ParsedTokenConfig,
RouteRateModelUpdate,
SortableEvent,
SpokePoolTargetBalance,
SpokeTargetBalanceUpdate,
TokenConfig,
Expand All @@ -41,8 +42,8 @@ type ConfigStoreUpdateSuccess = {
chainId: number;
searchEndBlock: number;
events: {
updatedTokenConfigEvents: Event[];
updatedGlobalConfigEvents: Event[];
updatedTokenConfigEvents: Log[];
updatedGlobalConfigEvents: Log[];
globalConfigUpdateTimes: number[];
};
};
Expand Down Expand Up @@ -430,12 +431,10 @@ export class AcrossConfigStoreClient extends BaseAbstractClient {

// Save new Global config updates.
for (let i = 0; i < updatedGlobalConfigEvents.length; i++) {
const event = updatedGlobalConfigEvents[i];
const args = {
blockNumber: event.blockNumber,
transactionIndex: event.transactionIndex,
logIndex: event.logIndex,
...spreadEvent(event.args),
const args = spreadEventWithBlockNumber(updatedGlobalConfigEvents[i]) as SortableEvent & {
key: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any;
};

if (args.key === utf8ToHex(GLOBAL_CONFIG_STORE_KEYS.MAX_RELAYER_REPAYMENT_LEAF_SIZE)) {
Expand Down
15 changes: 7 additions & 8 deletions src/clients/HubPoolClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import assert from "assert";
import { Contract, Event, EventFilter } from "ethers";
import { Contract, EventFilter } from "ethers";
import _ from "lodash";
import winston from "winston";
import { DEFAULT_CACHING_SAFE_LAG, DEFAULT_CACHING_TTL } from "../constants";
Expand All @@ -13,6 +13,7 @@ import {
DisputedRootBundle,
ExecutedRootBundle,
L1Token,
Log,
LpToken,
PendingRootBundle,
ProposedRootBundle,
Expand All @@ -38,7 +39,6 @@ import {
paginatedEventQuery,
shouldCache,
sortEventsDescending,
spreadEvent,
spreadEventWithBlockNumber,
toBN,
getTokenInfo,
Expand All @@ -52,7 +52,7 @@ type HubPoolUpdateSuccess = {
success: true;
currentTime: number;
pendingRootBundleProposal: PendingRootBundle;
events: Record<string, Event[]>;
events: Record<string, Log[]>;
searchEndBlock: number;
};
type HubPoolUpdateFailure = {
Expand Down Expand Up @@ -901,11 +901,10 @@ export class HubPoolClient extends BaseAbstractClient {
// only run iff a new token has been enabled. Will only append iff the info is not there already.
// Filter out any duplicate addresses. This might happen due to enabling, disabling and re-enabling a token.
if (eventsToQuery.includes("L1TokenEnabledForLiquidityProvision")) {
const uniqueL1Tokens = [
...Array.from(
new Set(events["L1TokenEnabledForLiquidityProvision"].map((event) => spreadEvent(event.args).l1Token))
),
];
const uniqueL1Tokens = dedupArray(
events["L1TokenEnabledForLiquidityProvision"].map((event) => String(event.args["l1Token"]))
);

const [tokenInfo, lpTokenInfo] = await Promise.all([
Promise.all(uniqueL1Tokens.map((l1Token: string) => fetchTokenInfo(l1Token, this.hubPool.provider))),
Promise.all(
Expand Down
76 changes: 39 additions & 37 deletions src/clients/SpokePoolClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Contract, Event, EventFilter } from "ethers";
import { Contract, EventFilter } from "ethers";
import winston from "winston";
import {
AnyObject,
Expand All @@ -20,22 +20,20 @@ import {
spreadEventWithBlockNumber,
} from "../utils/EventUtils";
import { validateFillForDeposit } from "../utils/FlowUtils";

import { ZERO_ADDRESS } from "../constants";
import {
Deposit,
DepositWithBlock,
Fill,
FillStatus,
FillWithBlock,
FilledV3RelayEvent,
Log,
RelayData,
RelayerRefundExecutionWithBlock,
RootBundleRelayWithBlock,
SlowFillRequestWithBlock,
SpeedUpWithBlock,
TokensBridged,
V3FundsDepositedEvent,
} from "../interfaces";
import { SpokePool } from "../typechain";
import { getNetworkName } from "../utils/NetworkUtils";
Expand All @@ -50,7 +48,7 @@ type SpokePoolUpdateSuccess = {
oldestTime: number;
firstDepositId: number;
latestDepositId: number;
events: Event[][];
events: Log[][];
searchEndBlock: number;
};
type SpokePoolUpdateFailure = {
Expand Down Expand Up @@ -510,7 +508,7 @@ export class SpokePoolClient extends BaseAbstractClient {
}

// Sort all events to ensure they are stored in a consistent order.
events.forEach((events: Event[]) => sortEventsAscendingInPlace(events));
events.forEach((events: Log[]) => sortEventsAscendingInPlace(events));

return {
success: true,
Expand Down Expand Up @@ -549,9 +547,7 @@ export class SpokePoolClient extends BaseAbstractClient {
}

if (eventsToQuery.includes("V3FundsDeposited")) {
const depositEvents = [
...((queryResults[eventsToQuery.indexOf("V3FundsDeposited")] ?? []) as V3FundsDepositedEvent[]),
];
const depositEvents = queryResults[eventsToQuery.indexOf("V3FundsDeposited")] ?? [];
if (depositEvents.length > 0) {
this.log("debug", `Using ${depositEvents.length} newly queried deposit events for chain ${this.chainId}`, {
earliestEvent: depositEvents[0].blockNumber,
Expand All @@ -560,15 +556,25 @@ export class SpokePoolClient extends BaseAbstractClient {

// For each deposit, resolve its quoteTimestamp to a block number on the HubPool.
// Don't bother filtering for uniqueness; the HubPoolClient handles this efficienctly.
const quoteBlockNumbers = await this.getBlockNumbers(depositEvents.map(({ args }) => args.quoteTimestamp));
const quoteBlockNumbers = await this.getBlockNumbers(
depositEvents.map(({ args }) => Number(args["quoteTimestamp"]))
);
for (const event of depositEvents) {
const rawDeposit = spreadEventWithBlockNumber(event);
const quoteBlockNumber = quoteBlockNumbers[Number(event.args["quoteTimestamp"])];

// Derive and append the common properties that are not part of the onchain event.
const quoteBlockNumber = quoteBlockNumbers[event.args.quoteTimestamp];
const deposit = { ...(rawDeposit as DepositWithBlock), originChainId: this.chainId, quoteBlockNumber };
const deposit = {
...spreadEventWithBlockNumber(event),
quoteBlockNumber,
originChainId: this.chainId,
// The following properties are placeholders to be updated immediately.
fromLiteChain: true,
toLiteChain: true,
} as DepositWithBlock;

deposit.fromLiteChain = this.isOriginLiteChain(deposit);
deposit.toLiteChain = this.isDestinationLiteChain(deposit);

if (deposit.outputToken === ZERO_ADDRESS) {
deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
}
Expand All @@ -587,16 +593,12 @@ export class SpokePoolClient extends BaseAbstractClient {
}
}

// TODO: When validating fills with deposits for the purposes of UBA flows, do we need to consider
// speed ups as well? For example, do we need to also consider that the speed up is before the fill
// timestamp to be applied for the fill? My brain hurts.
// Update deposits with speed up requests from depositor.
if (eventsToQuery.includes("RequestedSpeedUpV3Deposit")) {
const speedUpEvents = [...(queryResults[eventsToQuery.indexOf("RequestedSpeedUpV3Deposit")] ?? [])];
const speedUpEvents = queryResults[eventsToQuery.indexOf("RequestedSpeedUpV3Deposit")] ?? [];

for (const event of speedUpEvents) {
const rawEvent = spreadEventWithBlockNumber(event);
const speedUp = { ...rawEvent, originChainId: this.chainId } as SpeedUpWithBlock;
const speedUp = { ...spreadEventWithBlockNumber(event), originChainId: this.chainId } as SpeedUpWithBlock;
assign(this.speedUps, [speedUp.depositor, speedUp.depositId], [speedUp]);

// Find deposit hash matching this speed up event and update the deposit data associated with the hash,
Expand All @@ -615,10 +617,11 @@ export class SpokePoolClient extends BaseAbstractClient {
if (eventsToQuery.includes("RequestedV3SlowFill")) {
const slowFillRequests = queryResults[eventsToQuery.indexOf("RequestedV3SlowFill")];
for (const event of slowFillRequests) {
const slowFillRequest: SlowFillRequestWithBlock = {
...(spreadEventWithBlockNumber(event) as SlowFillRequestWithBlock),
const slowFillRequest = {
...spreadEventWithBlockNumber(event),
destinationChainId: this.chainId,
};
} as SlowFillRequestWithBlock;

const relayDataHash = getRelayDataHash(slowFillRequest, this.chainId);
if (this.slowFillRequests[relayDataHash] !== undefined) {
continue;
Expand All @@ -628,7 +631,7 @@ export class SpokePoolClient extends BaseAbstractClient {
}

if (eventsToQuery.includes("FilledV3Relay")) {
const fillEvents = [...((queryResults[eventsToQuery.indexOf("FilledV3Relay")] ?? []) as FilledV3RelayEvent[])];
const fillEvents = queryResults[eventsToQuery.indexOf("FilledV3Relay")] ?? [];

if (fillEvents.length > 0) {
this.log("debug", `Using ${fillEvents.length} newly queried fill events for chain ${this.chainId}`, {
Expand All @@ -640,9 +643,9 @@ export class SpokePoolClient extends BaseAbstractClient {
// test that the types are complete. A broader change in strategy for safely unpacking events will be introduced.
for (const event of fillEvents) {
const fill = {
...(spreadEventWithBlockNumber(event) as FillWithBlock),
...spreadEventWithBlockNumber(event),
destinationChainId: this.chainId,
};
} as FillWithBlock;

assign(this.fills, [fill.originChainId], [fill]);
assign(this.depositHashesToFills, [this.getDepositHash(fill)], [fill]);
Expand Down Expand Up @@ -808,7 +811,7 @@ export class SpokePoolClient extends BaseAbstractClient {
);
const tStop = Date.now();

const event = (query as V3FundsDepositedEvent[]).find((deposit) => deposit.args.depositId === depositId);
const event = query.find(({ args }) => args["depositId"] === depositId);
if (event === undefined) {
const srcChain = getNetworkName(this.chainId);
const dstChain = getNetworkName(destinationChainId);
Expand All @@ -817,19 +820,18 @@ export class SpokePoolClient extends BaseAbstractClient {
` between ${srcChain} blocks [${searchBounds.low}, ${searchBounds.high}]`
);
}
const partialDeposit = spreadEventWithBlockNumber(event) as DepositWithBlock;
const quoteBlockNumber = await this.getBlockNumber(partialDeposit.quoteTimestamp);

// Append destination token and realized lp fee to deposit.
const deposit: DepositWithBlock = {
...partialDeposit,
const deposit = {
...spreadEventWithBlockNumber(event),
originChainId: this.chainId,
quoteBlockNumber,
outputToken:
partialDeposit.outputToken === ZERO_ADDRESS
? this.getDestinationTokenForDeposit({ ...partialDeposit, originChainId: this.chainId })
: partialDeposit.outputToken,
};
quoteBlockNumber: await this.getBlockNumber(Number(event.args["quoteTimestamp"])),
fromLiteChain: true, // To be updated immediately afterwards.
toLiteChain: true, // To be updated immediately afterwards.
} as DepositWithBlock;

if (deposit.outputToken === ZERO_ADDRESS) {
deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
}
deposit.fromLiteChain = this.isOriginLiteChain(deposit);
deposit.toLiteChain = this.isDestinationLiteChain(deposit);

Expand Down
22 changes: 11 additions & 11 deletions src/clients/mocks/MockConfigStoreClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import assert from "assert";
import winston from "winston";
import { Contract, Event, ethers } from "ethers";
import { EventSearchConfig, MakeOptional, isDefined, utf8ToHex } from "../../utils";
import { Contract, ethers } from "ethers";
import { Log } from "../../interfaces";
import { getCurrentTime, EventSearchConfig, MakeOptional, isDefined, utf8ToHex } from "../../utils";
import {
AcrossConfigStoreClient,
ConfigStoreUpdate,
Expand Down Expand Up @@ -60,7 +61,7 @@ export class MockConfigStoreClient extends AcrossConfigStoreClient {
this.configStoreVersion = version;
}

async _update(): Promise<ConfigStoreUpdate> {
_update(): Promise<ConfigStoreUpdate> {
// Backwards compatibility for pre-existing MockConfigStoreClient users.
if (this.eventManager === null) {
return super._update();
Expand All @@ -72,23 +73,22 @@ export class MockConfigStoreClient extends AcrossConfigStoreClient {
// Ensure an array for every requested event exists, in the requested order.
// All requested event types must be populated in the array (even if empty).
const globalConfigUpdateTimes: number[] = [];
const _events: Event[][] = eventNames.map(() => []);
const _events: Log[][] = eventNames.map(() => []);
for (const event of this.eventManager.getEvents().flat()) {
const idx = eventNames.indexOf(event.event as string);
if (idx !== -1) {
_events[idx].push(event);
}

if (event.event === "UpdatedGlobalConfig") {
const block = await event.getBlock();
globalConfigUpdateTimes.push(block.timestamp);
globalConfigUpdateTimes.push(getCurrentTime());
pxrl marked this conversation as resolved.
Show resolved Hide resolved
}
}

// Transform 2d-events array into a record.
const events = Object.fromEntries(eventNames.map((eventName, idx) => [eventName, _events[idx]]));

return {
return Promise.resolve({
success: true,
chainId: this.chainId as number,
searchEndBlock: this.eventSearchConfig.toBlock || latestBlockSearched,
Expand All @@ -97,22 +97,22 @@ export class MockConfigStoreClient extends AcrossConfigStoreClient {
globalConfigUpdateTimes,
updatedTokenConfigEvents: events["UpdatedTokenConfig"],
},
};
});
}

updateGlobalConfig(key: string, value: string, overrides: EventOverrides = {}): Event {
updateGlobalConfig(key: string, value: string, overrides: EventOverrides = {}): Log {
return this.generateConfig("UpdatedGlobalConfig", utf8ToHex(key), value, overrides);
}

updateTokenConfig(key: string, value: string, overrides: EventOverrides = {}): Event {
updateTokenConfig(key: string, value: string, overrides: EventOverrides = {}): Log {
// Verify that the key is a valid address
if (ethers.utils.isAddress(key) === false) {
throw new Error(`Invalid address: ${key}`);
}
return this.generateConfig("UpdatedTokenConfig", key, value, overrides);
}

private generateConfig(event: string, key: string, value: string, overrides: EventOverrides = {}): Event {
private generateConfig(event: string, key: string, value: string, overrides: EventOverrides = {}): Log {
assert(this.eventManager !== null);

const topics = [key, value];
Expand Down
Loading
Loading