Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add redis caching support for getBalance #881

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions api/_polyfills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as fetch from "node-fetch";

// Required for @vercel/kv
if (!globalThis.fetch) {
(globalThis as any).fetch = fetch;
}

export {};
65 changes: 30 additions & 35 deletions api/_utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// _POLYFILLS MUST BE IMPORTED FIRST
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import * as _pFill from "./_polyfills";

import { AcceleratingDistributor__factory } from "@across-protocol/across-token/dist/typechain";
import {
ERC20__factory,
Expand All @@ -11,7 +15,6 @@ import { Log, Logging } from "@google-cloud/logging";
import axios from "axios";
import { BigNumber, ethers, providers, utils } from "ethers";
import { StructError, define } from "superstruct";

import enabledMainnetRoutesAsJson from "../src/data/routes_1_0xc186fA914353c44b2E33eBE05f21846F1048bEda.json";
import enabledGoerliRoutesAsJson from "../src/data/routes_5_0x0e2817C49698cc0874204AeDf7c72Be2Bb7fCD5d.json";

Expand All @@ -36,6 +39,7 @@ import {
defaultRelayerAddressOverride,
} from "./_constants";
import { PoolStateResult } from "./_types";
import { kv } from "@vercel/kv";
Copy link
Contributor Author

@james-a-morris james-a-morris Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setup/destroy of this redis is fully handled by vercel. It is federated in SFO, TX, and Singapore currently.


type LoggingUtility = sdk.relayFeeCalculator.Logger;

Expand Down Expand Up @@ -242,6 +246,7 @@ export const getTokenDetails = async (
};

export class InputError extends Error {}
export class ServerError extends Error {}

/**
* Resolves an Infura provider given the name of the ETH network
Expand Down Expand Up @@ -620,45 +625,35 @@ export const isRouteEnabled = (
* @param token The valid ERC20 token address on the given `chainId`.
* @returns A promise that resolves to the BigNumber of the balance
*/
export const getBalance = (
export const getCachedBalance = async (
chainId: string | number,
account: string,
token: string
): Promise<BigNumber> => {
return sdk.utils.getTokenBalance(
account,
token,
getProvider(Number(chainId)),
BLOCK_TAG_LAG
);
};

/**
* Resolves the cached balance of a given ERC20 token at a provided address. If no token is provided, the balance of the
* native currency will be returned.
* @param chainId The blockchain Id to query against
* @param account A valid Web3 wallet address
* @param token The valid ERC20 token address on the given `chainId`.
* @returns A promise that resolves to the BigNumber of the balance
*/
export const getCachedTokenBalance = async (
chainId: string | number,
account: string,
token: string
): Promise<BigNumber> => {
// Make the request to the vercel API.
const response = await axios.get<{ balance: string }>(
`${resolveVercelEndpoint()}/api/account-balance`,
{
params: {
chainId,
account,
token,
},
const key = `balance_${chainId}-${account}-${token}`.toLowerCase();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our keys are in checksum case, but I don't think it would hurt to make the key case insensitive.

const data = await kv.get<string>(key);
if (sdk.utils.isDefined(data)) {
return BigNumber.from(data);
} else {
const balance = await sdk.utils.getTokenBalance(
account,
token,
getProvider(Number(chainId)),
BLOCK_TAG_LAG // We should do this for consistency
);
try {
await kv.set(key, balance.toString(), {
ex: 60 * 5, // 5 minutes
});
getLogger().debug({
at: "_utils#getBalance",
message: `Cached balance for ${key}: ${balance}`,
});
} catch (_err) {
throw new ServerError();
}
);
// Return the balance
return BigNumber.from(response.data.balance);
return balance;
}
};

/**
Expand Down
60 changes: 0 additions & 60 deletions api/account-balance.ts

This file was deleted.

8 changes: 4 additions & 4 deletions api/limits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
getRelayerFeeDetails,
getCachedTokenPrice,
getTokenDetails,
getCachedTokenBalance,
maxBN,
minBN,
isRouteEnabled,
Expand All @@ -30,6 +29,7 @@ import {
getProvider,
HUB_POOL_CHAIN_ID,
ENABLED_ROUTES,
getCachedBalance,
getDefaultRelayerAddress,
sendResponse,
} from "./_utils";
Expand Down Expand Up @@ -165,19 +165,19 @@ const handler = async (
hubPool.callStatic.multicall(multicallInput, { blockTag: BLOCK_TAG_LAG }),
Promise.all(
fullRelayers.map((relayer) =>
getCachedTokenBalance(destinationChainId!, relayer, destinationToken)
getCachedBalance(destinationChainId!, destinationToken, relayer)
)
),
Promise.all(
transferRestrictedRelayers.map((relayer) =>
getCachedTokenBalance(destinationChainId!, relayer, destinationToken)
getCachedBalance(destinationChainId!, destinationToken, relayer)
)
),
Promise.all(
fullRelayers.map((relayer) =>
destinationChainId === "1"
? ethers.BigNumber.from("0")
: getCachedTokenBalance("1", relayer, l1Token)
: getCachedBalance("1", l1Token, relayer)
)
),
]);
Expand Down
4 changes: 2 additions & 2 deletions api/suggested-fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import {
HUB_POOL_CHAIN_ID,
ENABLED_ROUTES,
getSpokePoolAddress,
getCachedTokenBalance,
getDefaultRelayerAddress,
getCachedBalance,
} from "./_utils";

const SuggestedFeesQueryParamsSchema = type({
Expand Down Expand Up @@ -135,7 +135,7 @@ const handler = async (
`Could not resolve token address on ${destinationChainId} for ${l1Token}`
);
}
const balanceOfToken = await getCachedTokenBalance(
const balanceOfToken = await getCachedBalance(
destinationChainId,
relayer,
destinationToken
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"jose": "^4.9.3",
"lodash-es": "^4.17.21",
"luxon": "^3.3.0",
"node-fetch": "^3.3.2",
"numeral": "^2.0.6",
"react": "^17.0.2",
"react-device-detect": "^2.2.2",
Expand Down
39 changes: 39 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13719,6 +13719,11 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"

data-uri-to-buffer@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==

data-urls@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143"
Expand Down Expand Up @@ -16240,6 +16245,14 @@ fecha@^4.2.0:
resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd"
integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==

fetch-blob@^3.1.2, fetch-blob@^3.1.4:
version "3.2.0"
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
dependencies:
node-domexception "^1.0.0"
web-streams-polyfill "^3.0.3"

fetch-ponyfill@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893"
Expand Down Expand Up @@ -16537,6 +16550,13 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"

formdata-polyfill@^4.0.10:
version "4.0.10"
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
dependencies:
fetch-blob "^3.1.2"

[email protected]:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
Expand Down Expand Up @@ -21695,6 +21715,11 @@ node-dir@^0.1.17:
dependencies:
minimatch "^3.0.2"

node-domexception@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==

node-emoji@^1.10.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c"
Expand Down Expand Up @@ -21751,6 +21776,15 @@ node-fetch@^2.6.1, node-fetch@^2.6.7:
dependencies:
whatwg-url "^5.0.0"

node-fetch@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b"
integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==
dependencies:
data-uri-to-buffer "^4.0.0"
fetch-blob "^3.1.4"
formdata-polyfill "^4.0.10"

node-forge@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
Expand Down Expand Up @@ -27190,6 +27224,11 @@ web-encoding@^1.0.2, web-encoding@^1.0.6:
optionalDependencies:
"@zxing/text-encoding" "0.9.0"

web-streams-polyfill@^3.0.3:
version "3.2.1"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==

[email protected]:
version "1.7.4"
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.7.4.tgz#9419e606e38a9777443d4ce40506ebd796e06075"
Expand Down
Loading