diff --git a/api/_constants.ts b/api/_constants.ts index ee5cc58a5..8f1b20d4d 100644 --- a/api/_constants.ts +++ b/api/_constants.ts @@ -202,3 +202,5 @@ export const DOMAIN_CALLDATA_DELIMITER = "0x1dc0de"; export const DEFAULT_LITE_CHAIN_USD_MAX_BALANCE = "250000"; export const DEFAULT_LITE_CHAIN_USD_MAX_DEPOSIT = "25000"; + +export const DEFAULT_FILL_DEADLINE_BUFFER_SECONDS = 2.5 * 60 * 60; // 2.5 hours diff --git a/api/_fill-deadline.ts b/api/_fill-deadline.ts new file mode 100644 index 000000000..2016e28b4 --- /dev/null +++ b/api/_fill-deadline.ts @@ -0,0 +1,19 @@ +import { DEFAULT_FILL_DEADLINE_BUFFER_SECONDS } from "./_constants"; +import { getSpokePool } from "./_utils"; + +function getFillDeadlineBuffer(chainId: number) { + const bufferFromEnv = ( + JSON.parse(process.env.FILL_DEADLINE_BUFFER_SECONDS || "{}") as Record< + string, + string + > + )?.[chainId.toString()]; + return Number(bufferFromEnv ?? DEFAULT_FILL_DEADLINE_BUFFER_SECONDS); +} + +export async function getFillDeadline(chainId: number): Promise { + const fillDeadlineBuffer = getFillDeadlineBuffer(chainId); + const spokePool = getSpokePool(chainId); + const currentTime = await spokePool.callStatic.getCurrentTime(); + return Number(currentTime) + fillDeadlineBuffer; +} diff --git a/api/_utils.ts b/api/_utils.ts index 6e38465f1..4b94d2296 100644 --- a/api/_utils.ts +++ b/api/_utils.ts @@ -7,7 +7,6 @@ import { } from "@across-protocol/contracts/dist/typechain"; import acrossDeployments from "@across-protocol/contracts/dist/deployments/deployments.json"; import * as sdk from "@across-protocol/sdk"; -import { asL2Provider } from "@eth-optimism/sdk"; import { BALANCER_NETWORK_CONFIG, BalancerSDK, @@ -86,14 +85,18 @@ const { REACT_APP_HUBPOOL_CHAINID, REACT_APP_PUBLIC_INFURA_ID, REACT_APP_COINGECKO_PRO_API_KEY, - GAS_MARKUP, + BASE_FEE_MARKUP, + PRIORITY_FEE_MARKUP, VERCEL_ENV, LOG_LEVEL, } = process.env; -export const gasMarkup: { +export const baseFeeMarkup: { [chainId: string]: number; -} = GAS_MARKUP ? JSON.parse(GAS_MARKUP) : {}; +} = JSON.parse(BASE_FEE_MARKUP || "{}"); +export const priorityFeeMarkup: { + [chainId: string]: number; +} = JSON.parse(PRIORITY_FEE_MARKUP || "{}"); // Default to no markup. export const DEFAULT_GAS_MARKUP = 0; @@ -589,14 +592,47 @@ export const getHubPoolClient = () => { ); }; -export const getGasMarkup = (chainId: string | number) => { - if (typeof gasMarkup[chainId] === "number") { - return gasMarkup[chainId]; +export const getGasMarkup = ( + chainId: string | number +): { baseFeeMarkup: BigNumber; priorityFeeMarkup: BigNumber } => { + let _baseFeeMarkup: BigNumber | undefined; + let _priorityFeeMarkup: BigNumber | undefined; + if (typeof baseFeeMarkup[chainId] === "number") { + _baseFeeMarkup = utils.parseEther((1 + baseFeeMarkup[chainId]).toString()); + } + if (typeof priorityFeeMarkup[chainId] === "number") { + _priorityFeeMarkup = utils.parseEther( + (1 + priorityFeeMarkup[chainId]).toString() + ); + } + + // Otherwise, use default gas markup (or optimism's for OP stack). + if (_baseFeeMarkup === undefined) { + _baseFeeMarkup = utils.parseEther( + ( + 1 + + (sdk.utils.chainIsOPStack(Number(chainId)) + ? baseFeeMarkup[CHAIN_IDs.OPTIMISM] ?? DEFAULT_GAS_MARKUP + : DEFAULT_GAS_MARKUP) + ).toString() + ); + } + if (_priorityFeeMarkup === undefined) { + _priorityFeeMarkup = utils.parseEther( + ( + 1 + + (sdk.utils.chainIsOPStack(Number(chainId)) + ? priorityFeeMarkup[CHAIN_IDs.OPTIMISM] ?? DEFAULT_GAS_MARKUP + : DEFAULT_GAS_MARKUP) + ).toString() + ); } - return sdk.utils.chainIsOPStack(Number(chainId)) - ? gasMarkup[CHAIN_IDs.OPTIMISM] ?? DEFAULT_GAS_MARKUP - : DEFAULT_GAS_MARKUP; + // Otherwise, use default gas markup (or optimism's for OP stack). + return { + baseFeeMarkup: _baseFeeMarkup, + priorityFeeMarkup: _priorityFeeMarkup, + }; }; /** @@ -627,7 +663,7 @@ export const getRelayerFeeCalculator = ( ); }; -const getRelayerFeeCalculatorQueries = ( +export const getRelayerFeeCalculatorQueries = ( destinationChainId: number, overrides: Partial<{ spokePoolAddress: string; @@ -641,8 +677,7 @@ const getRelayerFeeCalculatorQueries = ( overrides.spokePoolAddress || getSpokePoolAddress(destinationChainId), overrides.relayerAddress, REACT_APP_COINGECKO_PRO_API_KEY, - getLogger(), - getGasMarkup(destinationChainId) + getLogger() ); }; @@ -654,12 +689,13 @@ const getRelayerFeeCalculatorQueries = ( * @param originChainId The origin chain that this token will be transferred from * @param destinationChainId The destination chain that this token will be transferred to * @param recipientAddress The address that will receive the transferred funds - * @param tokenPrice An optional overred price to prevent the SDK from creating its own call * @param message An optional message to include in the transfer - * @param relayerAddress An optional relayer address to use for the transfer - * @param gasUnits An optional gas unit to use for the transfer - * @param gasPrice An optional gas price to use for the transfer - * @returns The a promise to the relayer fee for the given `amount` of transferring `l1Token` to `destinationChainId` + * @param tokenPrice Price of input token in gas token units, used by SDK to compute gas fee percentages. + * @param relayerAddress Relayer address that SDK will use to simulate the fill transaction for gas cost estimation if + * the gasUnits is not defined. + * @param gasPrice Gas price that SDK will use to compute gas fee percentages. + * @param [gasUnits] An optional gas cost to use for the transfer. If not provided, the SDK will recompute this. + * @returns Relayer fee components for a fill of the given `amount` of transferring `l1Token` to `destinationChainId` */ export const getRelayerFeeDetails = async ( deposit: { @@ -671,10 +707,11 @@ export const getRelayerFeeDetails = async ( recipientAddress: string; message?: string; }, - tokenPrice?: number, - relayerAddress?: string, + tokenPrice: number, + relayerAddress: string, + gasPrice: sdk.utils.BigNumberish, gasUnits?: sdk.utils.BigNumberish, - gasPrice?: sdk.utils.BigNumberish + tokenGasCost?: sdk.utils.BigNumberish ): Promise => { const { inputToken, @@ -703,7 +740,8 @@ export const getRelayerFeeDetails = async ( relayerAddress, tokenPrice, gasPrice, - gasUnits + gasUnits, + tokenGasCost ); }; @@ -1931,18 +1969,34 @@ export function getCachedFillGasUsage( deposit.destinationChainId, overrides ); - const { nativeGasCost } = await relayerFeeCalculatorQueries.getGasCosts( + // We don't care about the gas token price or the token gas price, only the raw gas units. In the API + // we'll compute the gas price separately. + const gasCosts = await relayerFeeCalculatorQueries.getGasCosts( buildDepositForSimulation(deposit), overrides?.relayerAddress, { - omitMarkup: true, + // Scale the op stack L1 gas cost component by the base fee multiplier. + // Consider adding a new environment variable OP_STACK_L1_GAS_COST_MARKUP if we want finer-grained control. + opStackL1GasCostMultiplier: getGasMarkup(deposit.destinationChainId) + .baseFeeMarkup, } ); - return nativeGasCost; + return { + nativeGasCost: gasCosts.nativeGasCost, + tokenGasCost: gasCosts.tokenGasCost, + }; }; - return getCachedValue(cacheKey, ttl, fetchFn, (bnFromCache) => - BigNumber.from(bnFromCache) + return getCachedValue( + cacheKey, + ttl, + fetchFn, + (gasCosts: { nativeGasCost: BigNumber; tokenGasCost: BigNumber }) => { + return { + nativeGasCost: BigNumber.from(gasCosts.nativeGasCost), + tokenGasCost: BigNumber.from(gasCosts.tokenGasCost), + }; + } ); } @@ -1955,7 +2009,7 @@ export function latestGasPriceCache(chainId: number) { return makeCacheGetterAndSetter( buildInternalCacheKey("latestGasPriceCache", chainId), ttlPerChain[chainId] || ttlPerChain.default, - () => getMaxFeePerGas(chainId), + async () => (await getMaxFeePerGas(chainId)).maxFeePerGas, (bnFromCache) => BigNumber.from(bnFromCache) ); } @@ -1965,16 +2019,18 @@ export function latestGasPriceCache(chainId: number) { * @param chainId The chain ID to resolve the gas price for * @returns The gas price in the native currency of the chain */ -export async function getMaxFeePerGas(chainId: number): Promise { - if (sdk.utils.chainIsOPStack(chainId)) { - const l2Provider = asL2Provider(getProvider(chainId)); - return l2Provider.getGasPrice(); - } - const { maxFeePerGas } = await sdk.gasPriceOracle.getGasPriceEstimate( - getProvider(chainId), - chainId - ); - return maxFeePerGas; +export function getMaxFeePerGas( + chainId: number +): Promise { + const { + baseFeeMarkup: baseFeeMultiplier, + priorityFeeMarkup: priorityFeeMultiplier, + } = getGasMarkup(chainId); + return sdk.gasPriceOracle.getGasPriceEstimate(getProvider(chainId), { + chainId, + baseFeeMultiplier, + priorityFeeMultiplier, + }); } /** diff --git a/api/gas-prices.ts b/api/gas-prices.ts index 0b7a10534..fecf59694 100644 --- a/api/gas-prices.ts +++ b/api/gas-prices.ts @@ -1,31 +1,154 @@ import { VercelResponse } from "@vercel/node"; import { + buildDepositForSimulation, + getGasMarkup, getLogger, + getMaxFeePerGas, + getRelayerFeeCalculatorQueries, handleErrorCondition, - latestGasPriceCache, sendResponse, } from "./_utils"; import { TypedVercelRequest } from "./_types"; +import { ethers, providers, VoidSigner } from "ethers"; +import * as sdk from "@across-protocol/sdk"; +import { L2Provider } from "@eth-optimism/sdk/dist/interfaces/l2-provider"; import mainnetChains from "../src/data/chains_1.json"; +import { + DEFAULT_SIMULATED_RECIPIENT_ADDRESS, + TOKEN_SYMBOLS_MAP, +} from "./_constants"; +import { assert, Infer, object, optional, string } from "superstruct"; const chains = mainnetChains; +const QueryParamsSchema = object({ + symbol: optional(string()), +}); +type QueryParams = Infer; + const handler = async ( - _: TypedVercelRequest>, + { query }: TypedVercelRequest, response: VercelResponse ) => { const logger = getLogger(); + assert(query, QueryParamsSchema); + const tokenSymbol = query.symbol ?? "WETH"; try { + const chainIdsWithToken: { [chainId: string]: string } = Object.fromEntries( + chains + .map(({ chainId }) => { + const tokenAddress = + TOKEN_SYMBOLS_MAP?.[tokenSymbol as keyof typeof TOKEN_SYMBOLS_MAP] + ?.addresses[chainId]; + return [chainId, tokenAddress]; + }) + .filter(([, tokenAddress]) => tokenAddress !== undefined) + ); + // getMaxFeePerGas will return the gas price after including the baseFeeMultiplier. const gasPrices = await Promise.all( - chains.map(({ chainId }) => { - return latestGasPriceCache(chainId).get(); + Object.keys(chainIdsWithToken).map((chainId) => { + return getMaxFeePerGas(Number(chainId)); }) ); - const responseJson = Object.fromEntries( - chains.map(({ chainId }, i) => [chainId, gasPrices[i].toString()]) + const gasCosts = await Promise.all( + Object.entries(chainIdsWithToken).map( + async ([chainId, tokenAddress], i) => { + // This is a dummy deposit used to pass into buildDepositForSimulation() to build a fill transaction + // that we can simulate without reversion. The only parameter that matters is that the destinationChainId + // is set to the spoke pool's chain ID we'll be simulating the fill call on. + const depositArgs = { + amount: ethers.BigNumber.from(100), + inputToken: sdk.constants.ZERO_ADDRESS, + outputToken: tokenAddress, + recipientAddress: DEFAULT_SIMULATED_RECIPIENT_ADDRESS, + originChainId: 0, // Shouldn't matter for simulation + destinationChainId: Number(chainId), + }; + const deposit = buildDepositForSimulation(depositArgs); + const relayerFeeCalculatorQueries = getRelayerFeeCalculatorQueries( + Number(chainId) + ); + const opStackL1GasCostMultiplier = getGasMarkup( + Number(chainId) + ).baseFeeMarkup; + const { nativeGasCost, tokenGasCost } = + await relayerFeeCalculatorQueries.getGasCosts( + deposit, + relayerFeeCalculatorQueries.simulatedRelayerAddress, + { + // Pass in the already-computed gasPrice into this query so that the tokenGasCost includes + // the scaled gas price, + // e.g. tokenGasCost = nativeGasCost * (baseFee * baseFeeMultiplier + priorityFee). + gasPrice: gasPrices[i].maxFeePerGas, + opStackL1GasCostMultiplier, + } + ); + // OPStack chains factor in the L1 gas cost of including the L2 transaction in an L1 rollup batch + // into the total gas cost of the L2 transaction. + let opStackL1GasCost: ethers.BigNumber | undefined = undefined; + if (sdk.utils.chainIsOPStack(Number(chainId))) { + const provider = relayerFeeCalculatorQueries.provider; + const _unsignedTx = await sdk.utils.populateV3Relay( + relayerFeeCalculatorQueries.spokePool, + deposit, + relayerFeeCalculatorQueries.simulatedRelayerAddress + ); + const voidSigner = new VoidSigner( + relayerFeeCalculatorQueries.simulatedRelayerAddress, + relayerFeeCalculatorQueries.provider + ); + const unsignedTx = await voidSigner.populateTransaction({ + ..._unsignedTx, + gasLimit: nativeGasCost, // prevents additional gas estimation call + }); + opStackL1GasCost = await ( + provider as L2Provider + ).estimateL1GasCost(unsignedTx); + opStackL1GasCost = opStackL1GasCostMultiplier + .mul(opStackL1GasCost) + .div(sdk.utils.fixedPointAdjustment); + } + return { + nativeGasCost, + tokenGasCost, + opStackL1GasCost, + }; + } + ) ); + const responseJson = { + tokenSymbol, + ...Object.fromEntries( + Object.keys(chainIdsWithToken).map((chainId, i) => [ + chainId, + { + gasPrice: gasPrices[i].maxFeePerGas.toString(), + gasPriceComponents: { + maxFeePerGas: gasPrices[i].maxFeePerGas + .sub(gasPrices[i].maxPriorityFeePerGas) + .toString(), + priorityFeePerGas: gasPrices[i].maxPriorityFeePerGas.toString(), + baseFeeMultiplier: ethers.utils.formatEther( + getGasMarkup(chainId).baseFeeMarkup + ), + priorityFeeMultiplier: ethers.utils.formatEther( + getGasMarkup(chainId).priorityFeeMarkup + ), + opStackL1GasCostMultiplier: sdk.utils.chainIsOPStack( + Number(chainId) + ) + ? ethers.utils.formatEther(getGasMarkup(chainId).baseFeeMarkup) + : undefined, + }, + nativeGasCost: gasCosts[i].nativeGasCost.toString(), + tokenGasCost: gasCosts[i].tokenGasCost.toString(), + opStackL1GasCost: gasCosts[i]?.opStackL1GasCost?.toString(), + }, + ]) + ), + }; logger.debug({ at: "GasPrices", diff --git a/api/limits.ts b/api/limits.ts index 401f7fc28..fcfc29a33 100644 --- a/api/limits.ts +++ b/api/limits.ts @@ -1,7 +1,7 @@ import * as sdk from "@across-protocol/sdk"; import { VercelResponse } from "@vercel/node"; import { BigNumber, ethers } from "ethers"; -import { DEFAULT_SIMULATED_RECIPIENT_ADDRESS } from "./_constants"; +import { CHAIN_IDs, DEFAULT_SIMULATED_RECIPIENT_ADDRESS } from "./_constants"; import { TokenInfo, TypedVercelRequest } from "./_types"; import { object, assert, Infer, optional, string } from "superstruct"; @@ -164,7 +164,7 @@ const handler = async ( message, }; - const [tokenPriceNative, _tokenPriceUsd, latestBlock, gasUnits, gasPrice] = + const [tokenPriceNative, _tokenPriceUsd, latestBlock, gasCosts, gasPrice] = await Promise.all([ getCachedTokenPrice( l1Token.address, @@ -193,8 +193,9 @@ const handler = async ( depositArgs, tokenPriceNative, relayer, - gasUnits, - gasPrice + gasPrice, + gasCosts?.nativeGasCost, + gasCosts?.tokenGasCost ), callViaMulticall3(provider, multiCalls, { blockTag: latestBlock.number, @@ -358,13 +359,18 @@ const handler = async ( .mul(maxDepositShortDelay) .div(sdk.utils.fixedPointAdjustment); - const maximumDeposit = getMaxDeposit( - liquidReserves, - bufferedMaxDepositShortDelay, - limitsBufferMultiplier, - chainHasMaxBoundary, - routeInvolvesLiteChain - ); + // FIXME: Remove after campaign is complete + const maximumDeposit = + destinationChainId === CHAIN_IDs.ZK_SYNC && + computedOriginChainId === CHAIN_IDs.MAINNET + ? liquidReserves + : getMaxDeposit( + liquidReserves, + bufferedMaxDepositShortDelay, + limitsBufferMultiplier, + chainHasMaxBoundary, + routeInvolvesLiteChain + ); const responseJson = { // Absolute minimum may be overridden by the environment. diff --git a/api/suggested-fees.ts b/api/suggested-fees.ts index ceb724057..35a9ebdf4 100644 --- a/api/suggested-fees.ts +++ b/api/suggested-fees.ts @@ -5,6 +5,7 @@ import { type, assert, Infer, optional, string, enums } from "superstruct"; import { DEFAULT_SIMULATED_RECIPIENT_ADDRESS, DEFAULT_QUOTE_BLOCK_BUFFER, + CHAIN_IDs, } from "./_constants"; import { TypedVercelRequest } from "./_types"; import { @@ -38,6 +39,7 @@ import { AmountTooHighError, AmountTooLowError, } from "./_errors"; +import { getFillDeadline } from "./_fill-deadline"; const { BigNumber } = ethers; @@ -186,6 +188,7 @@ const handler = async ( [currentUt, nextUt, _quoteTimestamp, rawL1TokenConfig], tokenPriceUsd, limits, + fillDeadline, ] = await Promise.all([ callViaMulticall3(provider, multiCalls, { blockTag: quoteBlockNumber }), getCachedTokenPrice(l1Token.address, "usd"), @@ -202,6 +205,7 @@ const handler = async ( depositWithMessage ? relayer : undefined, depositWithMessage ? message : undefined ), + getFillDeadline(destinationChainId), ]); const { maxDeposit, maxDepositInstant, minDeposit, relayerFeeDetails } = limits; @@ -274,15 +278,30 @@ const handler = async ( )); } + // TODO: Remove after campaign is complete + /** + * Override estimated fill time for ZK Sync deposits. + * @todo Remove after campaign is complete + * @see Change in {@link ./limits.ts} + */ + const estimatedTimingOverride = + computedOriginChainId === CHAIN_IDs.MAINNET && + destinationChainId === CHAIN_IDs.ZK_SYNC && + amount.gte(limits.maxDepositShortDelay) + ? 9600 + : undefined; + const responseJson = { - estimatedFillTimeSec: amount.gte(maxDepositInstant) - ? resolveRebalanceTiming(String(destinationChainId)) - : resolveTiming( - String(computedOriginChainId), - String(destinationChainId), - inputToken.symbol, - amountInUsd - ), + estimatedFillTimeSec: + estimatedTimingOverride ?? + (amount.gte(maxDepositInstant) + ? resolveRebalanceTiming(String(destinationChainId)) + : resolveTiming( + String(computedOriginChainId), + String(destinationChainId), + inputToken.symbol, + amountInUsd + )), capitalFeePct: relayerFeeDetails.capitalFeePercent, capitalFeeTotal: relayerFeeDetails.capitalFeeTotal, relayGasFeePct: relayerFeeDetails.gasFeePercent, @@ -325,6 +344,7 @@ const handler = async ( maxDepositShortDelay: limits.maxDepositShortDelay, recommendedDepositInstant: limits.recommendedDepositInstant, }, + fillDeadline: fillDeadline.toString(), }; logger.debug({ diff --git a/src/utils/bridge.ts b/src/utils/bridge.ts index c2b5acd7b..d60e15127 100644 --- a/src/utils/bridge.ts +++ b/src/utils/bridge.ts @@ -1,7 +1,6 @@ import { ethers, BigNumber } from "ethers"; import { ChainId, - DEFAULT_FILL_DEADLINE_BUFFER_SECONDS, fixedPointAdjustment, referrerDelimiterHex, } from "./constants"; @@ -32,6 +31,7 @@ export type BridgeFees = { estimatedFillTimeSec: number; exclusiveRelayer: string; exclusivityDeadline: number; + fillDeadline: number; }; type GetBridgeFeesArgs = { @@ -77,6 +77,7 @@ export async function getBridgeFees({ estimatedFillTimeSec, exclusiveRelayer, exclusivityDeadline, + fillDeadline, } = await getApiEndpoint().suggestedFees( amount, getConfig().getTokenInfoBySymbol(fromChainId, inputTokenSymbol).address, @@ -103,6 +104,7 @@ export async function getBridgeFees({ estimatedFillTimeSec, exclusiveRelayer, exclusivityDeadline, + fillDeadline, }; } @@ -150,7 +152,7 @@ export type AcrossDepositArgs = { export type AcrossDepositV3Args = AcrossDepositArgs & { inputTokenAddress: string; outputTokenAddress: string; - fillDeadline?: number; + fillDeadline: number; exclusivityDeadline?: number; exclusiveRelayer?: string; }; @@ -236,7 +238,6 @@ export async function sendDepositV3Tx( const outputAmount = inputAmount.sub( inputAmount.mul(relayerFeePct).div(fixedPointAdjustment) ); - fillDeadline ??= await getFillDeadline(spokePool); const useExclusiveRelayer = exclusiveRelayer !== ethers.constants.AddressZero && @@ -350,7 +351,6 @@ export async function sendSwapAndBridgeTx( const outputAmount = inputAmount.sub( inputAmount.mul(relayerFeePct).div(fixedPointAdjustment) ); - fillDeadline ??= await getFillDeadline(spokePool); const tx = await swapAndBridge.populateTransaction.swapAndBridge( swapQuote.routerCalldata, @@ -424,15 +424,6 @@ export async function getSpokePoolAndVerifier({ }; } -async function getFillDeadline(spokePool: SpokePool): Promise { - const fillDeadlineBuffer = Number( - process.env.FILL_DEADLINE_BUFFER_SECONDS ?? - DEFAULT_FILL_DEADLINE_BUFFER_SECONDS - ); - const currentTime = await spokePool.callStatic.getCurrentTime(); - return Number(currentTime) + fillDeadlineBuffer; -} - async function _tagRefAndSignTx( tx: ethers.PopulatedTransaction, referrer: string, diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 40ec3d9e2..46b82c189 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -550,5 +550,3 @@ export const defaultSwapSlippage = Number( export const indexerApiBaseUrl = process.env.REACT_APP_INDEXER_BASE_URL || undefined; - -export const DEFAULT_FILL_DEADLINE_BUFFER_SECONDS = 2.5 * 60 * 60; // 2.5 hours diff --git a/src/utils/serverless-api/mocked/suggested-fees.mocked.ts b/src/utils/serverless-api/mocked/suggested-fees.mocked.ts index 4477ebf10..b02d76bfe 100644 --- a/src/utils/serverless-api/mocked/suggested-fees.mocked.ts +++ b/src/utils/serverless-api/mocked/suggested-fees.mocked.ts @@ -51,5 +51,6 @@ export async function suggestedFeesMockedApiCall( }, exclusiveRelayer: ethers.constants.AddressZero, exclusivityDeadline: 0, + fillDeadline: Date.now(), }; } diff --git a/src/utils/serverless-api/prod/suggested-fees.prod.ts b/src/utils/serverless-api/prod/suggested-fees.prod.ts index 7481cee24..3e5ea2bf5 100644 --- a/src/utils/serverless-api/prod/suggested-fees.prod.ts +++ b/src/utils/serverless-api/prod/suggested-fees.prod.ts @@ -89,5 +89,6 @@ export async function suggestedFeesApiCall( estimatedFillTimeSec, exclusiveRelayer, exclusivityDeadline, + fillDeadline: result.fillDeadline, }; } diff --git a/src/utils/serverless-api/types.ts b/src/utils/serverless-api/types.ts index 488b9afab..c85d4b2d5 100644 --- a/src/utils/serverless-api/types.ts +++ b/src/utils/serverless-api/types.ts @@ -58,6 +58,7 @@ export type SuggestedApiFeeReturnType = { estimatedFillTimeSec: number; exclusiveRelayer: string; exclusivityDeadline: number; + fillDeadline: number; }; export type SuggestedApiFeeType = ( diff --git a/src/views/Bridge/hooks/useBridgeAction.ts b/src/views/Bridge/hooks/useBridgeAction.ts index 868bd4bfb..85c1a110f 100644 --- a/src/views/Bridge/hooks/useBridgeAction.ts +++ b/src/views/Bridge/hooks/useBridgeAction.ts @@ -167,6 +167,7 @@ export function useBridgeAction( // Disabling until we update the contract. exclusiveRelayer: constants.AddressZero, exclusivityDeadline: 0, + fillDeadline: frozenFeeQuote.fillDeadline, }, networkMismatchHandler ); @@ -191,6 +192,7 @@ export function useBridgeAction( ...frozenDepositArgs, inputTokenAddress: frozenRoute.fromTokenAddress, outputTokenAddress: frozenRoute.toTokenAddress, + fillDeadline: frozenFeeQuote.fillDeadline, }, spokePool, networkMismatchHandler diff --git a/src/views/Bridge/utils.ts b/src/views/Bridge/utils.ts index e9882089d..c1c023768 100644 --- a/src/views/Bridge/utils.ts +++ b/src/views/Bridge/utils.ts @@ -1,4 +1,3 @@ -import { CHAIN_IDs } from "@across-protocol/constants"; import { BigNumber } from "ethers"; import { Route, @@ -151,10 +150,7 @@ export function getInitialRoute(filter: RouteFilter = {}) { const routeFromFilter = findEnabledRoute({ inputTokenSymbol: filter.inputTokenSymbol ?? - (filter?.fromChain === CHAIN_IDs.ALEPH_ZERO || - filter?.fromChain === CHAIN_IDs.POLYGON - ? "WETH" - : "ETH"), + (nonEthChains.includes(filter?.fromChain ?? -1) ? "WETH" : "ETH"), fromChain: filter.fromChain || hubPoolChainId, toChain: filter.toChain, }); diff --git a/yarn.lock b/yarn.lock index 6a3db5c4a..150bb9851 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,10 +16,10 @@ "@uma/common" "^2.17.0" hardhat "^2.9.3" -"@across-protocol/constants@^3.1.24": - version "3.1.24" - resolved "https://registry.yarnpkg.com/@across-protocol/constants/-/constants-3.1.24.tgz#01fe49330bb467dd01813387ddbac741bc74a035" - integrity sha512-guKtvIbif//vsmSZbwGubTWVtfkWiyWenr2sVyo63U/68GOW89ceJRLu4efLjeLVGiSrNAJtFUCv9dTwrrosWA== +"@across-protocol/constants@^3.1.24", "@across-protocol/constants@^3.1.25": + version "3.1.25" + resolved "https://registry.yarnpkg.com/@across-protocol/constants/-/constants-3.1.25.tgz#60d6d9814582ff91faf2b6d9f51d6dccb447b4ce" + integrity sha512-GpZoYn7hETYL2BPMM2GqXAer6+l/xuhder+pvpb00HJcb/sqCjF7vaaeKxjKJ3jKtyeulYmdu0NDkeNm5KbNWA== "@across-protocol/constants@^3.1.25": version "3.1.27"