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

fix: Handle L2 USDC symbol lookup #1509

Merged
merged 4 commits into from
May 10, 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
10 changes: 8 additions & 2 deletions src/clients/HubPoolClient.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -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;
}

/**
Expand Down
12 changes: 7 additions & 5 deletions src/clients/InventoryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/relayer/Relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}.` +
Expand Down
11 changes: 11 additions & 0 deletions src/utils/AddressUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case one of those symbols stops being used/populated in the map in the future.

Suggested change
return ["_USDC", "USDbC", "USDC.e"].find((token) => compareToken(TOKEN_SYMBOLS_MAP[token].addresses[chainId]));
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;
}
8 changes: 8 additions & 0 deletions test/InventoryClient.InventoryRebalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 () {
Expand Down
Loading