From 0b283aad9cf7346483cb1f419f98f480e1b1ffb6 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Thu, 12 Sep 2024 01:06:55 +0700 Subject: [PATCH] feat: cron job cache relayer balances --- api/_cache.ts | 19 ++++++++++- api/_utils.ts | 37 ++++++++------------ api/cron-cache-balances.ts | 69 ++++++++++++++++++++++++++++++++++++++ vercel.json | 6 ++++ 4 files changed, 107 insertions(+), 24 deletions(-) create mode 100644 api/cron-cache-balances.ts diff --git a/api/_cache.ts b/api/_cache.ts index b170042e3..5f6391034 100644 --- a/api/_cache.ts +++ b/api/_cache.ts @@ -66,7 +66,7 @@ export async function getCachedValue( ttl: number, fetcher: () => Promise, parser?: (value: T) => T -) { +): Promise { const cachedValue = await redisCache.get(key); if (cachedValue) { return parser ? parser(cachedValue) : cachedValue; @@ -76,3 +76,20 @@ export async function getCachedValue( await redisCache.set(key, value, ttl); return value; } + +export function makeCacheGetterAndSetter( + key: string, + ttl: number, + fetcher: () => Promise, + parser?: (value: T) => T +) { + return { + get: async () => { + return getCachedValue(key, ttl, fetcher, parser); + }, + set: async () => { + const value = await fetcher(); + await redisCache.set(key, value, ttl); + }, + }; +} diff --git a/api/_utils.ts b/api/_utils.ts index 18c868466..58dcac2b5 100644 --- a/api/_utils.ts +++ b/api/_utils.ts @@ -54,7 +54,11 @@ import { relayerFeeCapitalCostConfig, } from "./_constants"; import { PoolStateOfUser, PoolStateResult } from "./_types"; -import { buildInternalCacheKey, getCachedValue } from "./_cache"; +import { + buildInternalCacheKey, + getCachedValue, + makeCacheGetterAndSetter, +} from "./_cache"; type LoggingUtility = sdk.relayFeeCalculator.Logger; type RpcProviderName = keyof typeof rpcProvidersJson.providers.urls; @@ -1085,7 +1089,11 @@ export const getCachedTokenBalance = async ( account: string, token: string ): Promise => { - const balance = await getCachedLatestBalance(Number(chainId), token, account); + const balance = await latestBalanceCache( + Number(chainId), + token, + account + ).get(); return balance; }; @@ -1896,34 +1904,17 @@ export function getCachedLatestBlock(chainId: number) { ); } -export function getCachedGasPrice(chainId: number) { - const ttlPerChain = { - default: 5, - [CHAIN_IDs.ARBITRUM]: 2, - }; - - return getCachedValue( - buildInternalCacheKey("gasPrice", chainId), - ttlPerChain[chainId] || ttlPerChain.default, - async () => { - const gasPrice = await getProvider(chainId).getGasPrice(); - return gasPrice.mul(2); - }, - (bnFromCache) => BigNumber.from(bnFromCache) - ); -} - -export function getCachedLatestBalance( +export function latestBalanceCache( chainId: number, tokenAddress: string, address: string ) { const ttlPerChain = { - default: 30, - [CHAIN_IDs.MAINNET]: 30, + default: 60, + [CHAIN_IDs.MAINNET]: 60, }; - return getCachedValue( + return makeCacheGetterAndSetter( buildInternalCacheKey("latestBalance", tokenAddress, chainId, address), ttlPerChain[chainId] || ttlPerChain.default, () => getBalance(chainId, address, tokenAddress), diff --git a/api/cron-cache-balances.ts b/api/cron-cache-balances.ts new file mode 100644 index 000000000..a195b7527 --- /dev/null +++ b/api/cron-cache-balances.ts @@ -0,0 +1,69 @@ +import { VercelResponse } from "@vercel/node"; +import { ethers } from "ethers"; +import { TypedVercelRequest } from "./_types"; + +import { + HUB_POOL_CHAIN_ID, + getLogger, + handleErrorCondition, + latestBalanceCache, +} from "./_utils"; + +import mainnetChains from "../src/data/chains_1.json"; + +const handler = async ( + _: TypedVercelRequest>, + response: VercelResponse +) => { + const logger = getLogger(); + logger.debug({ + at: "CronCacheBalances", + message: "Starting cron job...", + }); + try { + const { + REACT_APP_FULL_RELAYERS, // These are relayers running a full auto-rebalancing strategy. + REACT_APP_TRANSFER_RESTRICTED_RELAYERS, // These are relayers whose funds stay put. + } = process.env; + + const fullRelayers = !REACT_APP_FULL_RELAYERS + ? [] + : (JSON.parse(REACT_APP_FULL_RELAYERS) as string[]).map((relayer) => { + return ethers.utils.getAddress(relayer); + }); + const transferRestrictedRelayers = !REACT_APP_TRANSFER_RESTRICTED_RELAYERS + ? [] + : (JSON.parse(REACT_APP_TRANSFER_RESTRICTED_RELAYERS) as string[]).map( + (relayer) => { + return ethers.utils.getAddress(relayer); + } + ); + + // Skip cron job on testnet + if (HUB_POOL_CHAIN_ID !== 1) { + return; + } + + for (const chain of mainnetChains) { + for (const token of chain.inputTokens) { + const setTokenBalance = async (relayer: string) => { + await latestBalanceCache(chain.chainId, relayer, token.address).set(); + }; + await Promise.all([ + Promise.all(fullRelayers.map(setTokenBalance)), + Promise.all(transferRestrictedRelayers.map(setTokenBalance)), + ]); + } + } + + logger.debug({ + at: "CronCacheBalances", + message: "Finished", + }); + response.status(200); + } catch (error: unknown) { + return handleErrorCondition("cron-cache-balances", response, logger, error); + } +}; + +export default handler; diff --git a/vercel.json b/vercel.json index 4c51df1e3..264a5b0b1 100644 --- a/vercel.json +++ b/vercel.json @@ -1,5 +1,11 @@ { "devCommand": "yarn dev", + "crons": [ + { + "path": "/api/cron-cache-balances", + "schedule": "* * * * *" + } + ], "rewrites": [ { "source": "/api/deposit/status",