From 8729c467cd54e258546b8953fc91ccb54d3fe940 Mon Sep 17 00:00:00 2001 From: nicholaspai Date: Tue, 10 Oct 2023 09:46:04 -0400 Subject: [PATCH] improve(relayer): Clear out token data explicitly and log token balances Based on an issue we're seeing where L1 to L2 rebalances are still getting duplicated, even after wrapping ETH, perhaps suggesting that the `tokenClient` is using stale data the logic written [here](https://github.com/across-protocol/relayer-v2/blob/master/src/relayer/RelayerClientHelper.ts#L159) should be reading updated balances post-ETH-unwrap but it may not. This PR adds more logs we can use to better debug --- src/clients/InventoryClient.ts | 3 -- src/clients/TokenClient.ts | 19 +++++++- src/clients/bridges/ArbitrumAdapter.ts | 7 +++ src/clients/bridges/ZKSyncAdapter.ts | 7 +++ .../bridges/op-stack/OpStackAdapter.ts | 7 +++ src/relayer/RelayerClientHelper.ts | 1 + src/relayer/RelayerConfig.ts | 44 ++++++++++--------- 7 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/clients/InventoryClient.ts b/src/clients/InventoryClient.ts index 95d078442..0f6bedafd 100644 --- a/src/clients/InventoryClient.ts +++ b/src/clients/InventoryClient.ts @@ -634,9 +634,6 @@ export class InventoryClient { } async wrapL2EthIfAboveThreshold(): Promise { - if (!this.isInventoryManagementEnabled()) { - return; - } this.log("Checking ETH->WETH Wrap status"); await this.adapterManager.wrapEthIfAboveThreshold(this.inventoryConfig, this.simMode); } diff --git a/src/clients/TokenClient.ts b/src/clients/TokenClient.ts index ffaec0934..0ae198946 100644 --- a/src/clients/TokenClient.ts +++ b/src/clients/TokenClient.ts @@ -123,6 +123,10 @@ export class TokenClient { this.tokenShortfall = {}; } + clearTokenData(): void { + this.tokenData = {}; + } + async setOriginTokenApprovals(): Promise { const tokensToApprove: { chainId: number; token: string }[] = []; Object.entries(this.tokenData).forEach(([_chainId, tokenMap]) => { @@ -191,7 +195,20 @@ export class TokenClient { } } - this.logger.debug({ at: "TokenBalanceClient", message: "TokenBalance client updated!" }); + // Remove allowance from token data when logging. + const balanceData = Object.fromEntries( + Object.entries(this.tokenData).map(([chainId, tokenData]) => { + return [ + chainId, + Object.fromEntries( + Object.entries(tokenData).map(([token, { balance }]) => { + return [token, balance]; + }) + ), + ]; + }) + ); + this.logger.debug({ at: "TokenBalanceClient", message: "TokenBalance client updated!", balanceData }); } async fetchTokenData(spokePoolClient: SpokePoolClient): Promise<{ diff --git a/src/clients/bridges/ArbitrumAdapter.ts b/src/clients/bridges/ArbitrumAdapter.ts index 68598f5aa..be533f377 100644 --- a/src/clients/bridges/ArbitrumAdapter.ts +++ b/src/clients/bridges/ArbitrumAdapter.ts @@ -214,6 +214,13 @@ export class ArbitrumAdapter extends BaseAdapter { const value = ethBalance.sub(target); this.logger.debug({ at: this.getName(), message: "Wrapping ETH", threshold, target, value, ethBalance }); return await this._wrapEthIfAboveThreshold(threshold, contract, value, simMode); + } else { + this.logger.debug({ + at: this.getName(), + message: "ETH balance below threhsold", + threshold, + ethBalance, + }); } return null; } diff --git a/src/clients/bridges/ZKSyncAdapter.ts b/src/clients/bridges/ZKSyncAdapter.ts index 9a6214005..a796a5291 100644 --- a/src/clients/bridges/ZKSyncAdapter.ts +++ b/src/clients/bridges/ZKSyncAdapter.ts @@ -246,6 +246,13 @@ export class ZKSyncAdapter extends BaseAdapter { const value = ethBalance.sub(target); this.logger.debug({ at: this.getName(), message: "Wrapping ETH", threshold, target, value, ethBalance }); return await this._wrapEthIfAboveThreshold(threshold, contract, value, simMode); + } else { + this.logger.debug({ + at: this.getName(), + message: "ETH balance below threhsold", + threshold, + ethBalance, + }); } return null; } diff --git a/src/clients/bridges/op-stack/OpStackAdapter.ts b/src/clients/bridges/op-stack/OpStackAdapter.ts index c5f2fe268..dcf2c6abf 100644 --- a/src/clients/bridges/op-stack/OpStackAdapter.ts +++ b/src/clients/bridges/op-stack/OpStackAdapter.ts @@ -154,6 +154,13 @@ export class OpStackAdapter extends BaseAdapter { const value = ethBalance.sub(target); this.logger.debug({ at: this.getName(), message: "Wrapping ETH", threshold, target, value, ethBalance }); return await this._wrapEthIfAboveThreshold(threshold, contract, value, simMode); + } else { + this.logger.debug({ + at: this.getName(), + message: "ETH balance below threhsold", + threshold, + ethBalance, + }); } return null; } diff --git a/src/relayer/RelayerClientHelper.ts b/src/relayer/RelayerClientHelper.ts index b995a9d8f..3b956667e 100644 --- a/src/relayer/RelayerClientHelper.ts +++ b/src/relayer/RelayerClientHelper.ts @@ -158,6 +158,7 @@ export async function updateRelayerClients(clients: RelayerClients, config: Rela // Update the token client after the inventory client has done its wrapping of L2 ETH to ensure latest WETH ballance. // The token client needs route data, so wait for update before checking approvals. + clients.tokenClient.clearTokenData(); await clients.tokenClient.update(); if (config.sendingRelaysEnabled) { await clients.tokenClient.setOriginTokenApprovals(); diff --git a/src/relayer/RelayerConfig.ts b/src/relayer/RelayerConfig.ts index d569ff863..43559a2a4 100644 --- a/src/relayer/RelayerConfig.ts +++ b/src/relayer/RelayerConfig.ts @@ -108,28 +108,30 @@ export class RelayerConfig extends CommonConfig { ); } }); - Object.keys(this.inventoryConfig.tokenConfig).forEach((l1Token) => { - Object.keys(this.inventoryConfig.tokenConfig[l1Token]).forEach((chainId) => { - const { targetPct, thresholdPct, unwrapWethThreshold, unwrapWethTarget } = - this.inventoryConfig.tokenConfig[l1Token][chainId]; - assert( - targetPct !== undefined && thresholdPct !== undefined, - `Bad config. Must specify targetPct, thresholdPct for ${l1Token} on ${chainId}` - ); - assert( - toBN(thresholdPct).lte(toBN(targetPct)), - `Bad config. thresholdPct<=targetPct for ${l1Token} on ${chainId}` - ); - this.inventoryConfig.tokenConfig[l1Token][chainId].targetPct = toBNWei(targetPct).div(100); - this.inventoryConfig.tokenConfig[l1Token][chainId].thresholdPct = toBNWei(thresholdPct).div(100); - if (unwrapWethThreshold !== undefined) { - this.inventoryConfig.tokenConfig[l1Token][chainId].unwrapWethThreshold = toBNWei(unwrapWethThreshold); - } - this.inventoryConfig.tokenConfig[l1Token][chainId].unwrapWethTarget = unwrapWethTarget - ? toBNWei(unwrapWethTarget) - : toBNWei(2); + if (this.inventoryConfig.tokenConfig !== undefined) { + Object.keys(this.inventoryConfig.tokenConfig).forEach((l1Token) => { + Object.keys(this.inventoryConfig.tokenConfig[l1Token]).forEach((chainId) => { + const { targetPct, thresholdPct, unwrapWethThreshold, unwrapWethTarget } = + this.inventoryConfig.tokenConfig[l1Token][chainId]; + assert( + targetPct !== undefined && thresholdPct !== undefined, + `Bad config. Must specify targetPct, thresholdPct for ${l1Token} on ${chainId}` + ); + assert( + toBN(thresholdPct).lte(toBN(targetPct)), + `Bad config. thresholdPct<=targetPct for ${l1Token} on ${chainId}` + ); + this.inventoryConfig.tokenConfig[l1Token][chainId].targetPct = toBNWei(targetPct).div(100); + this.inventoryConfig.tokenConfig[l1Token][chainId].thresholdPct = toBNWei(thresholdPct).div(100); + if (unwrapWethThreshold !== undefined) { + this.inventoryConfig.tokenConfig[l1Token][chainId].unwrapWethThreshold = toBNWei(unwrapWethThreshold); + } + this.inventoryConfig.tokenConfig[l1Token][chainId].unwrapWethTarget = unwrapWethTarget + ? toBNWei(unwrapWethTarget) + : toBNWei(2); + }); }); - }); + } } this.debugProfitability = DEBUG_PROFITABILITY === "true"; this.relayerGasMultiplier = toBNWei(RELAYER_GAS_MULTIPLIER || Constants.DEFAULT_RELAYER_GAS_MULTIPLIER);