Skip to content

Commit

Permalink
Merge branch 'master' into remove-can-refund-prefills
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholaspai authored Feb 10, 2025
2 parents ab3222e + c617920 commit 4d21daf
Show file tree
Hide file tree
Showing 30 changed files with 1,731 additions and 464 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@across-protocol/sdk",
"author": "UMA Team",
"version": "4.0.0",
"version": "4.1.8",
"license": "AGPL-3.0",
"homepage": "https://docs.across.to/reference/sdk",
"files": [
Expand Down Expand Up @@ -99,8 +99,8 @@
},
"dependencies": {
"@across-protocol/across-token": "^1.0.0",
"@across-protocol/constants": "^3.1.30",
"@across-protocol/contracts": "^3.0.25",
"@across-protocol/constants": "^3.1.32",
"@across-protocol/contracts": "4.0.0",
"@eth-optimism/sdk": "^3.3.1",
"@ethersproject/bignumber": "^5.7.0",
"@pinata/sdk": "^2.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/caching/Arweave/ArweaveClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class ArweaveClient {
// If the data does not match the validator, log a warning and return null.
this.logger.warn({
at: "ArweaveClient:get",
message: "Retrieved value from Arweave does not match the expected type",
message: `Retrieved value from Arweave does not match the expected type: ${e}`,
});
return null;
}
Expand Down
187 changes: 129 additions & 58 deletions src/clients/BundleDataClient/BundleDataClient.ts

Large diffs are not rendered by default.

78 changes: 48 additions & 30 deletions src/clients/BundleDataClient/utils/FillUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from "lodash";
import { providers } from "ethers";
import { Deposit, DepositWithBlock, Fill, FillWithBlock } from "../../../interfaces";
import { getBlockRangeForChain, isSlowFill, chainIsEvm, isValidEvmAddress, isDefined } from "../../../utils";
import { getBlockRangeForChain, isSlowFill, isValidEvmAddress, isDefined, chainIsEvm } from "../../../utils";
import { HubPoolClient } from "../../HubPoolClient";

export function getRefundInformationFromFill(
Expand All @@ -19,6 +19,7 @@ export function getRefundInformationFromFill(
let chainToSendRefundTo = isSlowFill(fill) ? fill.destinationChainId : fill.repaymentChainId;
// If the fill is for a deposit originating from the lite chain, the repayment chain is the origin chain
// regardless of whether it is a slow or fast fill (we ignore slow fills but this is for posterity).
// @note fill.repaymentChainId should already be set to originChainId but reset it to be safe.
if (fromLiteChain) {
chainToSendRefundTo = fill.originChainId;
}
Expand Down Expand Up @@ -49,24 +50,31 @@ export function getRefundInformationFromFill(

export function getRepaymentChainId(fill: Fill, matchedDeposit: Deposit): number {
// Lite chain deposits force repayment on origin chain.
return matchedDeposit.fromLiteChain ? fill.originChainId : fill.repaymentChainId;
return matchedDeposit.fromLiteChain ? matchedDeposit.originChainId : fill.repaymentChainId;
}

export function isEvmRepaymentValid(
fill: Fill,
export function forceDestinationRepayment(
repaymentChainId: number,
possibleRepaymentChainIds: number[] = []
matchedDeposit: Deposit & { quoteBlockNumber: number },
hubPoolClient: HubPoolClient
): boolean {
// Slow fills don't result in repayments so they're always valid.
if (isSlowFill(fill)) {
return true;
}
// Return undefined if the requested repayment chain ID is not in a passed in set of eligible chains. This can
// be used by the caller to narrow the chains to those that are not disabled in the config store.
if (possibleRepaymentChainIds.length > 0 && !possibleRepaymentChainIds.includes(repaymentChainId)) {
if (!matchedDeposit.fromLiteChain) {
try {
const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
matchedDeposit.inputToken,
matchedDeposit.originChainId,
matchedDeposit.quoteBlockNumber
);
hubPoolClient.getL2TokenForL1TokenAtBlock(l1TokenCounterpart, repaymentChainId, matchedDeposit.quoteBlockNumber);
// Repayment token could be found, this is a valid repayment chain.
return false;
} catch {
// Repayment token doesn't exist on repayment chain via PoolRebalanceRoutes, impossible to repay filler there.
return true;
}
} else {
return false;
}
return chainIsEvm(repaymentChainId) && isValidEvmAddress(fill.relayer);
}

// Verify that a fill sent to an EVM chain has a 20 byte address. If the fill does not, then attempt
Expand All @@ -75,20 +83,24 @@ export async function verifyFillRepayment(
_fill: FillWithBlock,
destinationChainProvider: providers.Provider,
matchedDeposit: DepositWithBlock,
possibleRepaymentChainIds: number[] = []
hubPoolClient: HubPoolClient
): Promise<FillWithBlock | undefined> {
const fill = _.cloneDeep(_fill);

const repaymentChainId = getRepaymentChainId(fill, matchedDeposit);
const validEvmRepayment = isEvmRepaymentValid(fill, repaymentChainId, possibleRepaymentChainIds);

// Case 1: Repayment chain is EVM and repayment address is valid EVM address.
if (validEvmRepayment) {
// Slow fills don't result in repayments so they're always valid.
if (isSlowFill(fill)) {
return fill;
}
// Case 2: Repayment chain is EVM but repayment address is not a valid EVM address. Attempt to switch repayment
// address to msg.sender of relay transaction.
else if (chainIsEvm(repaymentChainId) && !isValidEvmAddress(fill.relayer)) {

let repaymentChainId = getRepaymentChainId(fill, matchedDeposit);

// If repayment chain doesn't have a Pool Rebalance Route for the input token, then change the repayment
// chain to the destination chain.
if (forceDestinationRepayment(repaymentChainId, matchedDeposit, hubPoolClient)) {
repaymentChainId = fill.destinationChainId;
}

if (!isValidEvmAddress(fill.relayer)) {
// TODO: Handle case where fill was sent on non-EVM chain, in which case the following call would fail
// or return something unexpected. We'd want to return undefined here.
const fillTransaction = await destinationChainProvider.getTransaction(fill.transactionHash);
Expand All @@ -97,14 +109,20 @@ export async function verifyFillRepayment(
if (!isDefined(destinationRelayer) || !isValidEvmAddress(destinationRelayer)) {
return undefined;
}
// Otherwise, assume the relayer to be repaid is the msg.sender. We don't need to modify the repayment chain since
// the getTransaction() call would only succeed if the fill was sent on an EVM chain and therefore the msg.sender
// is a valid EVM address and the repayment chain is an EVM chain.
if (!matchedDeposit.fromLiteChain) {
repaymentChainId = fill.destinationChainId;
} else {
// We can't switch repayment chain for a lite chain deposit so just check whether the repayment chain,
// which should be the origin chain, is an EVM chain.
if (!chainIsEvm(repaymentChainId)) {
return undefined;
}
}
fill.relayer = destinationRelayer;
return fill;
}
// Case 3: Repayment chain is not an EVM chain, must be invalid.
else {
return undefined;
}

// Repayment address is now valid and repayment chain is either origin chain for lite chain or the destination
// chain for cases where the repayment address was invalid. Fill should be valid now.
fill.repaymentChainId = repaymentChainId;
return fill;
}
11 changes: 9 additions & 2 deletions src/clients/BundleDataClient/utils/SuperstructUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Infer,
object,
number,
optional,
Expand All @@ -13,6 +14,7 @@ import {
union,
type,
} from "superstruct";
import { UNDEFINED_MESSAGE_HASH } from "../../../constants";
import { BigNumber } from "../../../utils";

const PositiveIntegerStringSS = pattern(string(), /\d+/);
Expand Down Expand Up @@ -54,6 +56,7 @@ const SortableEventSS = {
};

const V3DepositSS = {
messageHash: defaulted(string(), UNDEFINED_MESSAGE_HASH),
fromLiteChain: defaulted(boolean(), false),
toLiteChain: defaulted(boolean(), false),
destinationChainId: number(),
Expand Down Expand Up @@ -82,17 +85,19 @@ const V3RelayExecutionEventInfoSS = object({
updatedOutputAmount: BigNumberType,
fillType: FillTypeSS,
updatedRecipient: string(),
updatedMessage: string(),
updatedMessage: optional(string()),
updatedMessageHash: defaulted(string(), UNDEFINED_MESSAGE_HASH),
});

const V3FillSS = {
...V3RelayDataSS,
message: optional(string()),
messageHash: defaulted(string(), UNDEFINED_MESSAGE_HASH),
destinationChainId: number(),
relayer: string(),
repaymentChainId: number(),
relayExecutionInfo: V3RelayExecutionEventInfoSS,
quoteTimestamp: number(),
messageHash: optional(string()),
};

const V3FillWithBlockSS = {
Expand Down Expand Up @@ -132,3 +137,5 @@ export const BundleDataSS = type({
bundleSlowFillsV3: nestedV3DepositRecordWithLpFeePctSS,
bundleFillsV3: nestedV3BundleFillsSS,
});

export type BundleData = Infer<typeof BundleDataSS>;
Loading

0 comments on commit 4d21daf

Please sign in to comment.