Skip to content

Commit

Permalink
fix: use a different rpc url for each chain (#230)
Browse files Browse the repository at this point in the history
* fix: use a different rpc url for each chain

* fix: catch errors when fetching balances

* refactor: skip iteration if no token is found

* fix: use injected rpc url for tokens not supporting multicall

* fix radix

---------

Co-authored-by: jmd3v <[email protected]>
  • Loading branch information
genaroibc and jmdev3 authored Oct 26, 2023
1 parent 083ff3a commit 53bfa60
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 37 deletions.
10 changes: 9 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -771,10 +771,18 @@ export class Squid {
}): Promise<TokenBalance[]> {
// remove invalid and duplicate chains and convert to number
const filteredChains = new Set(chains.map(Number).filter(c => !isNaN(c)));
const chainRpcUrls = this.chains.reduce(
(acc, chain) => ({
...acc,
[chain.chainId]: chain.rpc
}),
{}
);

return getAllEvmTokensBalance(
this.tokens.filter(t => filteredChains.has(Number(t.chainId))),
userAddress
userAddress,
chainRpcUrls
);
}

Expand Down
107 changes: 71 additions & 36 deletions src/services/getEvmBalances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ import {
type ContractAddress = `0x${string}`;

const CHAINS_WITHOUT_MULTICALL = [314, 3141]; // Filecoin, & Filecoin testnet
const CHAINS_WITHOUT_MULTICALL_RPC_URLS: Record<number, string> = {
314: "https://rpc.ankr.com/filecoin",
3141: "https://rpc.ankr.com/filecoin"
};

const getTokensBalanceSupportingMultiCall = async (
tokens: TokenData[],
chainRpcUrl: string,
userAddress?: ContractAddress
): Promise<TokenBalance[]> => {
if (!userAddress) return [];

const ETHEREUM_RPC_URL = "https://eth.meowrpc.com";
const provider = new ethers.providers.JsonRpcProvider(ETHEREUM_RPC_URL);
const provider = new ethers.providers.JsonRpcProvider(chainRpcUrl);

const contractCallContext: ContractCallContext[] = tokens.map(token => {
const isNativeToken =
Expand Down Expand Up @@ -57,35 +53,44 @@ const getTokensBalanceSupportingMultiCall = async (
tryAggregate: true
});

const { results } = (await multicallInstance.call(contractCallContext)) ?? {
results: {}
};
try {
const { results } = (await multicallInstance.call(contractCallContext)) ?? {
results: {}
};
const tokenBalances: TokenBalance[] = [];

const tokenBalances: TokenBalance[] = [];
for (const symbol in results) {
const data = results[symbol].callsReturnContext[0] ?? {};

for (const symbol in results) {
const data = results[symbol].callsReturnContext[0] ?? {};
const token = tokens.find(t => t.symbol === symbol);

const { decimals = 18, address = "0x" } =
tokens.find(t => t.symbol === symbol) ?? {};
if (!token) continue;

const mappedBalance: TokenBalance = {
symbol,
address,
decimals,
// balance in wei
balance: parseInt(data.returnValues[0]?.hex ?? "0", 16).toString()
};
const { decimals, address } = token;

tokenBalances.push(mappedBalance);
}
const mappedBalance: TokenBalance = {
symbol,
address,
decimals,
// balance in wei
balance: parseInt(data.returnValues[0]?.hex ?? "0", 10).toString()
};

tokenBalances.push(mappedBalance);
}

return tokenBalances;
return tokenBalances;
} catch (error) {
return [];
}
};

const getTokensBalanceWithoutMultiCall = async (
tokens: TokenData[],
userAddress: ContractAddress
userAddress: ContractAddress,
rpcUrlsPerChain: {
[chainId: string]: string;
}
): Promise<TokenBalance[]> => {
const balances: (TokenBalance | null)[] = await Promise.all(
tokens.map(async t => {
Expand All @@ -94,12 +99,14 @@ const getTokensBalanceWithoutMultiCall = async (
if (t.address === NATIVE_EVM_TOKEN_ADDRESS) {
balance = await fetchBalance({
token: t,
userAddress
userAddress,
rpcUrl: rpcUrlsPerChain[t.chainId]
});
} else {
balance = await fetchBalance({
token: t,
userAddress
userAddress,
rpcUrl: rpcUrlsPerChain[t.chainId]
});
}

Expand All @@ -116,7 +123,10 @@ const getTokensBalanceWithoutMultiCall = async (

export const getAllEvmTokensBalance = async (
evmTokens: TokenData[],
userAddress: string
userAddress: string,
chainRpcUrls: {
[chainId: string]: string;
}
): Promise<TokenBalance[]> => {
try {
// Some tokens don't support multicall, so we need to fetch them with Promise.all
Expand All @@ -136,14 +146,39 @@ export const getAllEvmTokensBalance = async (
const tokensNotSupportingMulticall = splittedTokensByMultiCallSupport[0];
const tokensSupportingMulticall = splittedTokensByMultiCallSupport[1];

const tokensMulticall = await getTokensBalanceSupportingMultiCall(
tokensSupportingMulticall,
userAddress as ContractAddress
const tokensByChainId = tokensSupportingMulticall.reduce(
(groupedTokens, token) => {
if (!groupedTokens[token.chainId]) {
groupedTokens[token.chainId] = [];
}

groupedTokens[token.chainId].push(token);

return groupedTokens;
},
{} as Record<string, TokenData[]>
);

const tokensMulticall: TokenBalance[] = [];

for (const chainId in tokensByChainId) {
const tokens = tokensByChainId[chainId];
const rpcUrl = chainRpcUrls[chainId];

if (!rpcUrl) continue;

const tokensBalances = await getTokensBalanceSupportingMultiCall(
tokens,
rpcUrl,
userAddress as ContractAddress
);

tokensMulticall.push(...tokensBalances);
}
const tokensNotMultiCall = await getTokensBalanceWithoutMultiCall(
tokensNotSupportingMulticall,
userAddress as ContractAddress
userAddress as ContractAddress,
chainRpcUrls
);

return [...tokensMulticall, ...tokensNotMultiCall];
Expand All @@ -156,16 +191,16 @@ export const getAllEvmTokensBalance = async (
type FetchBalanceParams = {
token: TokenData;
userAddress: ContractAddress;
rpcUrl: string;
};

async function fetchBalance({
token,
userAddress
userAddress,
rpcUrl
}: FetchBalanceParams): Promise<TokenBalance | null> {
try {
const provider = new ethers.providers.JsonRpcProvider(
CHAINS_WITHOUT_MULTICALL_RPC_URLS[Number(token.chainId)]
);
const provider = new ethers.providers.JsonRpcProvider(rpcUrl);

const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
const tokenContract = new ethers.Contract(
Expand Down

0 comments on commit 53bfa60

Please sign in to comment.