diff --git a/api/_utils.ts b/api/_utils.ts index f403e508a..fb658cd46 100644 --- a/api/_utils.ts +++ b/api/_utils.ts @@ -1885,7 +1885,7 @@ export function getLimitsBufferMultiplier(symbol: string) { limitsBufferMultipliers[symbol] || "0.8" ); const multiplierCap = ethers.utils.parseEther("1"); - return bufferMultiplier.gt(multiplierCap) ? multiplierCap : bufferMultiplier; + return minBN(bufferMultiplier, multiplierCap); } export function getChainInputTokenMaxBalanceInUsd( @@ -2023,13 +2023,12 @@ export function getCachedOpStackL1DataFee( relayerAddress: string; }> ) { - // This should be longer than the length of 1 block on Ethereum mainnet which is how often the L1 data fee should - // change since its based on the L1 base fee. However, this L1 data fee is mostly affected by the L1 base fee which - // should only change by 12.5% at most per block. + // The L1 data fee should change after each Ethereum block since its based on the L1 base fee. + // However, the L1 base fee should only change by 12.5% at most per block. // We set this higher than the secondsPerUpdate value in the cron cache gas prices job which will update this // more frequently. const ttlPerChain = { - default: 30, + default: 60, }; const cacheKey = buildInternalCacheKey( diff --git a/api/cron-cache-gas-prices.ts b/api/cron-cache-gas-prices.ts index d4facddbd..6e5f5cb92 100644 --- a/api/cron-cache-gas-prices.ts +++ b/api/cron-cache-gas-prices.ts @@ -31,11 +31,18 @@ const updateIntervalsSecPerChain = { default: 5, }; -// Set lower than TTL in getCachedOpStackL1DataFee and getCachedNativeGasCost +// Set lower than TTL in getCachedOpStackL1DataFee +// Set lower than the L1 block time so we can try to get as up to date L1 data fees based on L1 base fees as possible. const updateL1DataFeeIntervalsSecPerChain = { default: 10, }; +// Set lower than TTL in getCachedNativeGasCost. This should rarely change so we should just make sure +// we keep this cache warm. +const updateNativeGasCostIntervalsSecPerChain = { + default: 30, +}; + const maxDurationSec = 60; const getDepositArgsForChainId = (chainId: number, tokenAddress: string) => { @@ -113,10 +120,9 @@ const handler = async ( }; /** - * @notice Updates the L1 data fee and L2 gas cost caches every `updateL1DataFeeIntervalsSecPerChain` seconds + * @notice Updates the L1 data fee gas cost cache every `updateL1DataFeeIntervalsSecPerChain` seconds * up to `maxDurationSec` seconds. - * @dev This function will also update the L2 gas costs because this value is required to get the L1 data fee. - * @param chainId Chain to estimate gas price for + * @param chainId Chain to estimate l1 data fee for * @param outputTokenAddress This output token will be used to construct a fill transaction to simulate * gas costs for. */ @@ -143,6 +149,32 @@ const handler = async ( } }; + /** + * @notice Updates the native gas cost cache every `updateNativeGasCostIntervalsSecPerChain` seconds + * up to `maxDurationSec` seconds. + * @param chainId Chain to estimate gas cost for + * @param outputTokenAddress This output token will be used to construct a fill transaction to simulate + * gas costs for. + */ + const updateNativeGasCostPromise = async ( + chainId: number, + outputTokenAddress: string + ): Promise => { + const secondsPerUpdate = updateNativeGasCostIntervalsSecPerChain.default; + const depositArgs = getDepositArgsForChainId(chainId, outputTokenAddress); + const cache = getCachedNativeGasCost(depositArgs); + + while (true) { + const diff = Date.now() - functionStart; + // Stop after `maxDurationSec` seconds + if (diff >= maxDurationSec * 1000) { + break; + } + await cache.set(); + await utils.delay(secondsPerUpdate); + } + }; + const lineaDestinationRoutes = availableRoutes.filter( ({ destinationChainId }) => destinationChainId === CHAIN_IDs.LINEA ); @@ -164,18 +196,25 @@ const handler = async ( ) ), Promise.all( - mainnetChains.map((chain) => { + mainnetChains.map(async (chain) => { const routesToChain = availableRoutes.filter( ({ destinationChainId }) => destinationChainId === chain.chainId ); const outputTokensForChain = routesToChain.map( ({ destinationToken }) => destinationToken ); - return Promise.all( - outputTokensForChain.map((outputToken) => - updateL1DataFeePromise(chain.chainId, outputToken) - ) - ); + await Promise.all([ + Promise.all( + outputTokensForChain.map((outputToken) => + updateNativeGasCostPromise(chain.chainId, outputToken) + ) + ), + Promise.all( + outputTokensForChain.map((outputToken) => + updateL1DataFeePromise(chain.chainId, outputToken) + ) + ), + ]); }) ), ]); diff --git a/api/cron-ping-endpoints.ts b/api/cron-ping-endpoints.ts index 7656eddb0..6bdc1fe2d 100644 --- a/api/cron-ping-endpoints.ts +++ b/api/cron-ping-endpoints.ts @@ -24,6 +24,51 @@ const endpoints = [ }, updateIntervalSec: 10, }, + { + url: "https://preview.across.to/api/swap/auth", + params: { + amount: ethers.utils.parseUnits("1", 6).toString(), + tradeType: "minOutput", + inputToken: TOKEN_SYMBOLS_MAP.USDC.addresses[CHAIN_IDs.ARBITRUM], + originChainId: CHAIN_IDs.ARBITRUM, + outputToken: TOKEN_SYMBOLS_MAP.USDC.addresses[CHAIN_IDs.OPTIMISM], + destinationChainId: CHAIN_IDs.OPTIMISM, + depositor: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + skipOriginTxEstimation: true, + refundOnOrigin: false, + }, + updateIntervalSec: 10, + }, + { + url: "https://preview.across.to/api/swap/permit", + params: { + amount: ethers.utils.parseUnits("1", 6).toString(), + tradeType: "minOutput", + inputToken: TOKEN_SYMBOLS_MAP.USDC.addresses[CHAIN_IDs.ARBITRUM], + originChainId: CHAIN_IDs.ARBITRUM, + outputToken: TOKEN_SYMBOLS_MAP.USDC.addresses[CHAIN_IDs.OPTIMISM], + destinationChainId: CHAIN_IDs.OPTIMISM, + depositor: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + skipOriginTxEstimation: true, + refundOnOrigin: false, + }, + updateIntervalSec: 10, + }, + { + url: "https://preview.across.to/api/swap", + params: { + amount: ethers.utils.parseUnits("1", 6).toString(), + tradeType: "minOutput", + inputToken: TOKEN_SYMBOLS_MAP.USDC.addresses[CHAIN_IDs.ARBITRUM], + originChainId: CHAIN_IDs.ARBITRUM, + outputToken: TOKEN_SYMBOLS_MAP.USDC.addresses[CHAIN_IDs.OPTIMISM], + destinationChainId: CHAIN_IDs.OPTIMISM, + depositor: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + skipOriginTxEstimation: true, + refundOnOrigin: false, + }, + updateIntervalSec: 10, + }, ]; const maxDurationSec = 60; diff --git a/api/limits.ts b/api/limits.ts index fc9b8e318..d9dd4f06c 100644 --- a/api/limits.ts +++ b/api/limits.ts @@ -301,8 +301,10 @@ const handler = async ( getLpCushion(l1Token.symbol, computedOriginChainId, destinationChainId), l1Token.decimals ); - liquidReserves = liquidReserves.sub(lpCushion); - if (liquidReserves.lt(0)) liquidReserves = ethers.BigNumber.from(0); + liquidReserves = maxBN( + liquidReserves.sub(lpCushion), + ethers.BigNumber.from(0) + ); maxDepositInstant = minBN(maxDepositInstant, liquidReserves); maxDepositShortDelay = minBN(maxDepositShortDelay, liquidReserves); @@ -417,6 +419,14 @@ const handler = async ( capitalFeeTotal: relayerFeeDetails.capitalFeeTotal, capitalFeePercent: relayerFeeDetails.capitalFeePercent, }, + gasFeeDetails: tokenGasCost + ? { + nativeGasCost: nativeGasCost!.toString(), // Should exist if tokenGasCost exists + opStackL1GasCost: opStackL1GasCost?.toString(), + gasPrice: gasPrice.toString(), + tokenGasCost: tokenGasCost.toString(), + } + : undefined, }; logger.debug({ at: "Limits", diff --git a/package.json b/package.json index 887f348db..c6103cccb 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@across-protocol/constants": "^3.1.24", "@across-protocol/contracts": "^3.0.19", "@across-protocol/contracts-v3.0.6": "npm:@across-protocol/contracts@3.0.6", - "@across-protocol/sdk": "^3.4.10-beta.1", + "@across-protocol/sdk": "^3.4.10", "@amplitude/analytics-browser": "^2.3.5", "@balancer-labs/sdk": "1.1.6-beta.16", "@emotion/react": "^11.13.0", diff --git a/vercel.json b/vercel.json index 00a7f48ec..fa7fa812a 100644 --- a/vercel.json +++ b/vercel.json @@ -25,7 +25,7 @@ "rewrites": [ { "source": "/api/deposit/status", - "destination": "https://public.api.across.to/deposit/status" + "destination": "https://indexer.across.to/deposit/status" } ], "redirects": [ diff --git a/yarn.lock b/yarn.lock index deb950404..699f87e8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -116,10 +116,10 @@ yargs "^17.7.2" zksync-web3 "^0.14.3" -"@across-protocol/sdk@^3.4.10-beta.1": - version "3.4.10-beta.1" - resolved "https://registry.yarnpkg.com/@across-protocol/sdk/-/sdk-3.4.10-beta.1.tgz#81d56458d97dec424e2fe51730f8ae3953c84e6c" - integrity sha512-c4tD6RQBKiok4fAK99Kh69B5+PIcAz0DLaAhfWxInRxW4kBeAKSrOtjETxuYN1wRZ89qRsGx+N+7c/wDpeQDxg== +"@across-protocol/sdk@^3.4.10": + version "3.4.10" + resolved "https://registry.yarnpkg.com/@across-protocol/sdk/-/sdk-3.4.10.tgz#b74c551f1625afccc10f5b792f1f61395771cf40" + integrity sha512-kM+RyTNVXzS4dl5zwJZh6es5FTouN1nECd0cckE7Z/FzEFdMmQmCn4I1Ojgt4gmE5AuUBZef4/11ZvT8uRmutQ== dependencies: "@across-protocol/across-token" "^1.0.0" "@across-protocol/constants" "^3.1.27"