Skip to content

Commit

Permalink
feat: add pool rebalance and relayer refund leaf execution (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrice32 authored May 23, 2022
1 parent cb8a78c commit f0f36d0
Show file tree
Hide file tree
Showing 13 changed files with 760 additions and 22 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ artifacts
cache
coverage*
gasReporterOutput.json
dist
20 changes: 13 additions & 7 deletions src/clients/HubPoolClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export class HubPoolClient {
return this.pendingRootBundle !== undefined && this.pendingRootBundle.unclaimedPoolRebalanceLeafCount > 0;
}

getProposedRootBundles() {
return this.proposedRootBundles;
}

getSpokePoolForBlock(block: number, chain: number): string {
if (!this.crossChainContracts[chain]) throw new Error(`No cross chain contracts set for ${chain}`);
const mostRecentSpokePoolUpdatebeforeBlock = (
Expand Down Expand Up @@ -182,15 +186,17 @@ export class HubPoolClient {
) as ExecutedRootBundle[];
}

getNextBundleStartBlockNumber(chainIdList: number[], latestMainnetBlock: number, chainId: number): number {
getLatestFullyExecutedRootBundle(latestMainnetBlock: number): ProposedRootBundle | undefined {
// Search for latest ProposeRootBundleExecuted event followed by all of its RootBundleExecuted event suggesting
// that all pool rebalance leaves were executed. This ignores any proposed bundles that were partially executed.
const latestFullyExecutedPoolRebalanceRoot = sortEventsDescending(this.proposedRootBundles).find(
(rootBundle: ProposedRootBundle) => {
if (rootBundle.blockNumber > latestMainnetBlock) return false;
return this.isRootBundleValid(rootBundle, latestMainnetBlock);
}
) as ProposedRootBundle;
return sortEventsDescending(this.proposedRootBundles).find((rootBundle: ProposedRootBundle) => {
if (rootBundle.blockNumber > latestMainnetBlock) return false;
return this.isRootBundleValid(rootBundle, latestMainnetBlock);
});
}

getNextBundleStartBlockNumber(chainIdList: number[], latestMainnetBlock: number, chainId: number): number {
const latestFullyExecutedPoolRebalanceRoot = this.getLatestFullyExecutedRootBundle(latestMainnetBlock);

// If no event, then we can return a conservative default starting block like 0,
// or we could throw an Error.
Expand Down
2 changes: 1 addition & 1 deletion src/clients/MultiCallerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export class MultiCallerClient {
buildMultiCallBundle(transactions: AugmentedTransaction[]) {
// Validate all transactions in the batch have the same target contract.
const target = transactions[0].contract;
if (transactions.every((tx) => tx.contract.address != target.address)) {
if (transactions.every((tx) => tx.contract.address !== target.address)) {
this.logger.error({
at: "MultiCallerClient",
message: "some transactions in the bundle contain different targets",
Expand Down
33 changes: 32 additions & 1 deletion src/clients/SpokePoolClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import { toBN, Event, ZERO_ADDRESS, winston, paginatedEventQuery, spreadEventWit

import { AcrossConfigStoreClient } from "./ConfigStoreClient";
import { Deposit, DepositWithBlock, Fill, SpeedUp, FillWithBlock, TokensBridged } from "../interfaces/SpokePool";
import { RootBundleRelayWithBlock, RelayerRefundExecutionWithBlock } from "../interfaces/SpokePool";

export class SpokePoolClient {
private deposits: { [DestinationChainId: number]: Deposit[] } = {};
private fills: Fill[] = [];
private speedUps: { [depositorAddress: string]: { [depositId: number]: SpeedUp[] } } = {};
private depositRoutes: { [originToken: string]: { [DestinationChainId: number]: boolean } } = {};
private tokensBridged: TokensBridged[] = [];
private rootBundleRelays: RootBundleRelayWithBlock[] = [];
private relayerRefundExecutions: RelayerRefundExecutionWithBlock[] = [];
public isUpdated: boolean = false;

public firstBlockToSearch: number;
Expand Down Expand Up @@ -76,6 +79,14 @@ export class SpokePoolClient {
return this.fills.filter((fill: Fill) => fill.relayer === relayer);
}

getRootBundleRelays() {
return this.rootBundleRelays;
}

getRelayerRefundExecutions() {
return this.relayerRefundExecutions;
}

appendMaxSpeedUpSignatureToDeposit(deposit: Deposit) {
const maxSpeedUp = this.speedUps[deposit.depositor]?.[deposit.depositId].reduce((prev, current) =>
prev.newRelayerFeePct.gt(current.newRelayerFeePct) ? prev : current
Expand Down Expand Up @@ -141,12 +152,22 @@ export class SpokePoolClient {
this.log("debug", "Updating client", { searchConfig, depositRouteSearchConfig, spokePool: this.spokePool.address });
if (searchConfig.fromBlock > searchConfig.toBlock) return; // If the starting block is greater than the ending block return.

const [depositEvents, speedUpEvents, fillEvents, enableDepositsEvents, tokensBridgedEvents] = await Promise.all([
const [
depositEvents,
speedUpEvents,
fillEvents,
enableDepositsEvents,
tokensBridgedEvents,
relayedRootBundleEvents,
executedRelayerRefundRootEvents,
] = await Promise.all([
paginatedEventQuery(this.spokePool, this.spokePool.filters.FundsDeposited(), searchConfig),
paginatedEventQuery(this.spokePool, this.spokePool.filters.RequestedSpeedUpDeposit(), searchConfig),
paginatedEventQuery(this.spokePool, this.spokePool.filters.FilledRelay(), searchConfig),
paginatedEventQuery(this.spokePool, this.spokePool.filters.EnabledDepositRoute(), depositRouteSearchConfig),
paginatedEventQuery(this.spokePool, this.spokePool.filters.TokensBridged(), depositRouteSearchConfig),
paginatedEventQuery(this.spokePool, this.spokePool.filters.RelayedRootBundle(), searchConfig),
paginatedEventQuery(this.spokePool, this.spokePool.filters.ExecutedRelayerRefundRoot(), searchConfig),
]);

for (const event of tokensBridgedEvents) {
Expand Down Expand Up @@ -196,11 +217,21 @@ export class SpokePoolClient {
const enableDeposit = spreadEvent(event);
assign(this.depositRoutes, [enableDeposit.originToken, enableDeposit.destinationChainId], enableDeposit.enabled);
}

for (const event of relayedRootBundleEvents) {
this.rootBundleRelays.push(spreadEvent(event));
}

for (const event of executedRelayerRefundRootEvents) {
this.relayerRefundExecutions.push(spreadEvent(event));
}

this.firstBlockToSearch = searchConfig.toBlock + 1; // Next iteration should start off from where this one ended.

this.isUpdated = true;
this.log("debug", "Client updated!");
}

public hubPoolClient() {
return this.configStoreClient.hubPoolClient;
}
Expand Down
Loading

0 comments on commit f0f36d0

Please sign in to comment.