Skip to content

Commit

Permalink
fix(ProfitClient): Fix fill amount USD computation (across-protocol#1688
Browse files Browse the repository at this point in the history
)

The ProfitClient currently assumes that the value of a fill can be
determined from the input token price * the output amount of the
output token. This is roughly correct for most Across deposits, but
falls over when the deposit includes an in-protocol swap to an output
token with a different number of decimals.

This was exposed on an Optimism deposit for inputToken USDC, outputToken
AERO on Base.

Deposit hash:
  0x4a3febcfb764467d9eae261b3a3938137db383289fe328050a2871eb407e1147
  • Loading branch information
pxrl authored and sameersubudhi committed Sep 10, 2024
1 parent 014060e commit be30f6e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
29 changes: 20 additions & 9 deletions src/clients/ProfitClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
BigNumber,
formatFeePct,
getCurrentTime,
getNetworkName,
isDefined,
min,
winston,
Expand Down Expand Up @@ -390,16 +391,26 @@ export class ProfitClient {
}

// Return USD amount of fill amount for deposited token, should always return in wei as the units.
getFillAmountInUsd(deposit: Deposit, fillAmount = deposit.outputAmount): BigNumber {
const l1TokenInfo = this.hubPoolClient.getTokenInfoForDeposit(deposit);
if (!l1TokenInfo) {
const { inputToken } = deposit;
throw new Error(
`ProfitClient#getFillAmountInUsd missing l1TokenInfo for deposit with origin token: ${inputToken}`
);
getFillAmountInUsd(
deposit: Pick<Deposit, "destinationChainId" | "outputToken" | "outputAmount">
): BigNumber | undefined {
const { destinationChainId, outputToken, outputAmount } = deposit;
let l1Token: L1Token;

try {
l1Token = this.hubPoolClient.getL1TokenInfoForL2Token(outputToken, destinationChainId);
} catch {
this.logger.info({
at: "ProfitClient#getFillAmountInUsd",
message: `Cannot resolve output token ${outputToken} on ${getNetworkName(destinationChainId)}.`,
});
return undefined;
}
const tokenPriceInUsd = this.getPriceOfToken(l1TokenInfo.symbol);
return fillAmount.mul(tokenPriceInUsd).div(bn10.pow(l1TokenInfo.decimals));

const tokenPriceInUsd = this.getPriceOfToken(l1Token.symbol);

// The USD amount of a fill must be normalised to 18 decimals, so factor out the token's own decimal promotion.
return outputAmount.mul(tokenPriceInUsd).div(bn10.pow(l1Token.decimals));
}

async getFillProfitability(
Expand Down
11 changes: 11 additions & 0 deletions src/relayer/Relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ export class Relayer {

// Ensure that the individual deposit meets the minimum deposit confirmation requirements for its value.
const fillAmountUsd = profitClient.getFillAmountInUsd(deposit);
if (!isDefined(fillAmountUsd)) {
this.logger.debug({
at: "Relayer::evaluateFill",
message: `Skipping ${srcChain} deposit due to uncertain fill amount.`,
destinationChainId,
outputToken: deposit.outputToken,
transactionHash: deposit.transactionHash,
});
return false;
}

const { minConfirmations } = minDepositConfirmations[originChainId].find(({ usdThreshold }) =>
usdThreshold.gte(fillAmountUsd)
);
Expand Down

0 comments on commit be30f6e

Please sign in to comment.