diff --git a/src/clients/HubPoolClient.ts b/src/clients/HubPoolClient.ts index c1ed98df7..9f5fdecfc 100644 --- a/src/clients/HubPoolClient.ts +++ b/src/clients/HubPoolClient.ts @@ -1,7 +1,7 @@ import { clients, interfaces } from "@across-protocol/sdk-v2"; import { Contract } from "ethers"; import winston from "winston"; -import { MakeOptional, EventSearchConfig, getTokenInfo, getL1TokenInfo } from "../utils"; +import { MakeOptional, EventSearchConfig, getTokenInfo, getL1TokenInfo, getUsdcSymbol } from "../utils"; import { IGNORED_HUB_EXECUTED_BUNDLES, IGNORED_HUB_PROPOSED_BUNDLES } from "../common"; import { L1Token } from "../interfaces"; @@ -41,7 +41,13 @@ export class HubPoolClient extends clients.HubPoolClient { * @returns Token info for the given token address on the L2 chain including symbol and decimal. */ getTokenInfoForAddress(tokenAddress: string, chain: number): L1Token { - return getTokenInfo(tokenAddress, chain); + const tokenInfo = getTokenInfo(tokenAddress, chain); + // @dev Temporarily handle case where an L2 token for chain ID can map to more than one TOKEN_SYMBOLS_MAP + // entry. For example, L2 Bridged USDC maps to both the USDC and USDC.e/USDbC entries in TOKEN_SYMBOLS_MAP. + if (tokenInfo.symbol.toLowerCase() === "usdc" && chain !== this.chainId) { + tokenInfo.symbol = getUsdcSymbol(tokenAddress, chain); + } + return tokenInfo; } /** diff --git a/src/clients/InventoryClient.ts b/src/clients/InventoryClient.ts index 87238fdf5..9539188ce 100644 --- a/src/clients/InventoryClient.ts +++ b/src/clients/InventoryClient.ts @@ -818,10 +818,10 @@ export class InventoryClient { for (const [_chainId, rebalances] of Object.entries(groupedRebalances)) { const chainId = Number(_chainId); mrkdwn += `*Rebalances sent to ${getNetworkName(chainId)}:*\n`; - for (const { l1Token, l2Token, amount, targetPct, thresholdPct, cumulativeBalance, hash } of rebalances) { - const tokenInfo = this.hubPoolClient.getTokenInfoForL1Token(l1Token); + for (const { l2Token, amount, targetPct, thresholdPct, cumulativeBalance, hash, chainId } of rebalances) { + const tokenInfo = this.hubPoolClient.getTokenInfoForAddress(l2Token, chainId); if (!tokenInfo) { - throw new Error(`InventoryClient::rebalanceInventoryIfNeeded no L1 token info for token ${l1Token}`); + `InventoryClient::rebalanceInventoryIfNeeded no token info for L2 token ${l2Token} on chain ${chainId}`; } const { symbol, decimals } = tokenInfo; const formatter = createFormatFunction(2, 4, false, decimals); @@ -842,9 +842,11 @@ export class InventoryClient { const chainId = Number(_chainId); mrkdwn += `*Insufficient amount to rebalance to ${getNetworkName(chainId)}:*\n`; for (const { l1Token, l2Token, balance, cumulativeBalance, amount } of rebalances) { - const tokenInfo = this.hubPoolClient.getTokenInfoForL1Token(l1Token); + const tokenInfo = this.hubPoolClient.getTokenInfoForAddress(l2Token, chainId); if (!tokenInfo) { - throw new Error(`InventoryClient::rebalanceInventoryIfNeeded no L1 token info for token ${l1Token}`); + throw new Error( + `InventoryClient::rebalanceInventoryIfNeeded no token info for L2 token ${l2Token} on chain ${chainId}` + ); } const { symbol, decimals } = tokenInfo; const formatter = createFormatFunction(2, 4, false, decimals); diff --git a/src/relayer/Relayer.ts b/src/relayer/Relayer.ts index 52c8152b3..d12326b90 100644 --- a/src/relayer/Relayer.ts +++ b/src/relayer/Relayer.ts @@ -849,7 +849,7 @@ export class Relayer { .div(deposit.inputAmount); const totalFeePct = formatFeePct(_totalFeePct); const { symbol: outputTokenSymbol, decimals: outputTokenDecimals } = - this.clients.hubPoolClient.getTokenInfoForDeposit(deposit); + this.clients.hubPoolClient.getTokenInfoForAddress(deposit.outputToken, deposit.destinationChainId); const _outputAmount = createFormatFunction(2, 4, false, outputTokenDecimals)(deposit.outputAmount.toString()); msg += ` and output ${_outputAmount} ${outputTokenSymbol}, with depositor ${depositor}.` + diff --git a/src/utils/AddressUtils.ts b/src/utils/AddressUtils.ts index 7d0b429c0..22259bed8 100644 --- a/src/utils/AddressUtils.ts +++ b/src/utils/AddressUtils.ts @@ -100,6 +100,17 @@ export function getTokenAddressWithCCTP( return getTokenAddress(l1Token, hubChainId, l2ChainId); } +/** + * Get the USDC symbol for the given token address and chain ID. + * @param l2Token A Web3 token address (not case sensitive) + * @param chainId A chain Id to reference + * @returns Either USDC (if native) or USDbC/USDC.e (if bridged) or undefined if the token address is not recognized. + */ +export function getUsdcSymbol(l2Token: string, chainId: number): string | undefined { + const compareToken = (token?: string) => isDefined(token) && compareAddressesSimple(l2Token, token); + return ["_USDC", "USDbC", "USDC.e"].find((token) => compareToken(TOKEN_SYMBOLS_MAP[token].addresses[chainId])); +} + export function checkAddressChecksum(tokenAddress: string): boolean { return ethers.utils.getAddress(tokenAddress) === tokenAddress; } diff --git a/test/InventoryClient.InventoryRebalance.ts b/test/InventoryClient.InventoryRebalance.ts index d6603ece7..883b34912 100644 --- a/test/InventoryClient.InventoryRebalance.ts +++ b/test/InventoryClient.InventoryRebalance.ts @@ -104,6 +104,10 @@ describe("InventoryClient: Rebalancing inventory", async function () { await configStoreClient.update(); hubPoolClient = new MockHubPoolClient(spyLogger, hubPool, configStoreClient); + enabledChainIds.forEach((chainId) => { + hubPoolClient.mapTokenInfo(l2TokensForWeth[chainId], "WETH", 18); + hubPoolClient.mapTokenInfo(l2TokensForUsdc[chainId], "USDC", 6); + }); await hubPoolClient.update(); adapterManager = new MockAdapterManager(null, null, null, null); @@ -349,6 +353,10 @@ describe("InventoryClient: Rebalancing inventory", async function () { beforeEach(async function () { // Sub in a nested USDC config for the existing USDC single-token config. inventoryConfig.tokenConfig[mainnetUsdc] = usdcConfig; + + enabledChainIds.forEach((chainId) => { + hubPoolClient.mapTokenInfo(nativeUSDC[chainId], "USDC", 6); + }); }); it("Correctly resolves 1:many token mappings", async function () {